カスタムフィールドのname
、username
およびvalue
を取得する次の(機能する)クエリがあります。
// Get a db connection.
$db = JFactory::getDbo();
// Create a new query object.
$query = $db->getQuery(true);
// Select name and username from USERS table and value from FIELDS_VALUES table.
// Define USERS table as ju
// Define FIELD_VALUES as jfv and match id and item_id to perform an inner join
// Set condition
// Set Order as ascending
$query
->select(array('ju.username', 'ju.name', 'jfv.value'))
->from($db->quoteName('#__users', 'ju'))
->join('INNER', $db->quoteName('#__fields_values', 'jfv') . ' ON (' . $db->quoteName('ju.id') . ' = ' . $db->quoteName('jfv.item_id') . ')')
->where($db->quoteName('jfv.value') . ' LIKE ' . $db->quote('C%'))
->order($db->quoteName('ju.username') . ' ASC');
// Reset the query using our newly populated query object.
$db->setQuery($query);
// Load results as a list of objects in an array
$results = $db->loadObjectList();
print_r($results);
これは、アパートの建物でユーザーのname
とusername
をdoor
、floor
とstaircase
とともに表示するために使用されます。この場合、staircase
"C"のすべての人々。
テーブル #__fields_values
はユーザー48
:
field_id | item_id | value |
============================
2 | 48 | 5 |
============================
3 | 48 | C |
============================
4 | 48 | 2 |
============================
上記の表では:
door
値は5
staircase
値はC
ですfloor
値は2
私の問題は、私の出力が次のようになることです:
Array (
[0] => stdClass Object (
[username] => C1 [name] => NameOfTheGuy [value] => C
)...
しかし、私が必要とするのは、floor
値ではなく、staircase
値を持つことです。
列内の値に基づいてエイリアスを割り当てることはできますか(jvf.staircase
の場合jfv.field_id = 3
)?または、私がやりたいことを達成するためのより良い方法はありますか?
未加工のピボットクエリ
_SELECT ju.username,
ju.name,
MAX(IF(jfv.field_id = 2, jfv.value, NULL)) AS `door`,
MAX(IF(jfv.field_id = 3, jfv.value, NULL)) AS `staircase`,
MAX(IF(jfv.field_id = 4, jfv.value, NULL)) AS `floor`
FROM `#__users` AS ju
INNER JOIN `#__fields_values` AS jfv ON ju.id = jfv.item_id
GROUP BY ju.username ASC, ju.name
HAVING MAX(IF(jfv.field_id = 3, jfv.value, NULL)) LIKE 'C%'
_
可能な結果セット:
_| username | name | door | staircase | floor |
| -------- | ----- | ---- | --------- | ----- |
| FollaKY | Folla | 5 | C | 2 |
_
PHP/Joomlaコード(未テスト テスト済み):
_$db = JFactory::getDbo();
$juUsername = $db->qn("ju.username"); // Cache this (D.R.Y.)
$juName = $db->qn("ju.name"); // Cache this (D.R.Y.)
$jfvFieldId = $db->qn("jfv.field_id"); // Cache this (D.R.Y.)
$jfvValue = $db->qn("jfv.value"); // Cache this (D.R.Y.)
$query = $db->getQuery(true)
->select([
$juUsername,
$juName,
"MAX(IF($jfvFieldId = 2, $jfvValue, NULL)) AS " . $db->qn('door'),
"MAX(IF($jfvFieldId = 3, $jfvValue, NULL)) AS " . $db->qn('staircase'),
"MAX(IF($jfvFieldId = 4, $jfvValue, NULL)) AS " . $db->qn('floor')
])
->from($db->qn('#__users', 'ju'))
->innerJoin($db->qn('#__fields_values', 'jfv') . ' ON ' . $db->qn('ju.id') . ' = ' . $db->qn('jfv.item_id'))
->group([
"$juUsername ASC", // declare the sorting order here
$juName
])
->having("MAX(IF($jfvFieldId = 3, $jfvValue, NULL) LIKE " . $db->q("C%"));
// echo $query->dump(); // uncomment if you want to confirm the rendered query
try {
$db->setQuery($query);
echo "<pre>";
var_export($db->loadObjectList());
} catch (Exception $e) {
JFactory::getApplication()->enqueueMessage("Query Syntax Error: " . $e->getMessage(), 'error'); // never show getMessage() to public
}
_
手順の説明:
users
テーブルを_fields_values
_テーブルに結合します。これは、users
行ごとに1対多の関係です。 _INNER JOIN
_の使用は、_LEFT JOIN
_とは異なります。これは、_INNER JOIN
_が、関連する_fields_values
_行が1つもないusers
行を省略しているためです。
同じユーザーに複数の行が表示されないようにするために、_GROUP BY
_が実装されています。これにより、ユーザーごとに「集計データ」(つまり、そのユーザーに固有の_fields_values
_データのクラウド|マス|クラスター|パイル)が作成されます。
_fields_values
_の行固有の値に基づいて、結果セットの対象となるユーザーを決定するには、集計データで比較を実行する必要があります。 HAVING
句は、すべての集計データをチェックします。集約行に_field_id
_の_3
_がない場合、その行にはNULL
の値が割り当てられます(このサブプロセスのスコープ内)。 _field_id
_が_3
_の場合、元のvalue
が維持されます。これにより、_field_id
_の_3
_の行とvalue
のNULL
の行がない限り、value
はNULL
になります)MAX()
-この唯一の値に比較ロジックを適用します。
結合、グループ化、およびフィルターのすべてが完了したので、今度は実際の結果セットを修正します。この時点では、SELECT
句に送信されている「集約データ」がまだありますが、結果セットに「集約データ」を含めて配信することはできません(つまり、行をフラット化する必要があります)。 HAVING
句と同じfilter&maxテクニックを使用して、結果セットの各行に対して生成する特定の各列を手動で記述し、AS
の後に任意の列エイリアスを割り当てます。できました。
これをコード化する方法はいくつかあります...
MAX()
内のIF
ステートメントの代わりに_CASE-WHEN
_ステートメントが表示される場合がありますが、これらは論理的に交換可能です。GROUP BY
_句の内部で実行できますが、_ORDER BY
_句を使用して実行することもできます。$db->qn()
呼び出しのは実際にこのクエリに必要なのは、テーブルまたは列の名前にモンキーレンチ文字が含まれていないか、または MySQL予約キーワードのリスト に含まれていないためです。ご覧のとおり、これらのすべての連結と引用呼び出しは構文を大きく膨らませ、タイプミスの読み取りと検索をはるかに困難にします。これが私のプロジェクトの場合、バックティックを生成する呼び出しをすべて削除する傾向があります。また、_C%
_などの静的文字列の引用呼び出しも削除しますが、これはすべて個人の好みの問題です。