クエリ:アイテムごとに複数の集計をカウントする
-
07-07-2019 - |
質問
多くの場合、データベースアイテムのリストと各アイテムに関する特定の集計番号を表示する必要があります。たとえば、Stack Overflowでタイトルテキストを入力すると、関連質問リストが表示されます。このリストには、関連するエントリのタイトルと、各タイトルの単一の集計された回答数が表示されます。
同様の問題がありますが、複数の集計が必要です。ユーザーオプションに応じて3つの形式のいずれかでアイテムのリストを表示したい:
- アイテムの名前(合計15、所有者13)
- アイテムの名前(合計15個)
- 私のアイテムの名前(私が所有する13)
私のデータベースは:
- アイテム:itemId、itemName、ownerId
- カテゴリ:catId、catName
- map :mapId、itemId、catId
以下のクエリは、カテゴリ名、カテゴリごとのアイテムIDの数を取得します
SELECT
categories.catName,
COUNT(map.itemId) AS item_count
FROM categories
LEFT JOIN map
ON categories.catId = map.catId
GROUP BY categories.catName
これは以下を取得します:カテゴリ名、このowner_idのみのカテゴリごとのアイテムIDの数
SELECT categories.catName,
COUNT(map.itemId) AS owner_item_count
FROM categories
LEFT JOIN map
ON categories.catId = map.catId
LEFT JOIN items
ON items.itemId = map.itemId
WHERE owner = @ownerId
GROUP BY categories.catId
しかし、単一のクエリで同時に取得するにはどうすればよいですか?つまり、カテゴリ名、カテゴリごとのアイテムIDの数、このowner_idのみのカテゴリごとのアイテムIDの数
ボーナス。これらのいずれかのcatId count!= 0のみをオプションで取得するにはどうすればよいですか? <!> quot; WHERE item_count <!> lt; <!> gt; 0 <!> quot;取得:
MySQL said: Documentation
#1054 - Unknown column 'rid_count' in 'where clause'
解決
コツ:1または0であることがわかっている値のSUM()
を計算することは、値が1である行のCOUNT()
と同等です。また、ブール比較は1または0を返すことがわかります。 (またはNULL)。
SELECT c.catname, COUNT(m.catid) AS item_count,
SUM(i.ownerid = @ownerid) AS owner_item_count
FROM categories c
LEFT JOIN map m USING (catid)
LEFT JOIN items i USING (itemid)
GROUP BY c.catid;
ボーナスの質問に関しては、外部結合の代わりに単純に内部結合を行うことができます。つまり、map
に少なくとも1つの行があるカテゴリのみが返されます。
SELECT c.catname, COUNT(m.catid) AS item_count,
SUM(i.ownerid = @ownerid) AS owner_item_count
FROM categories c
INNER JOIN map m USING (catid)
INNER JOIN items i USING (itemid)
GROUP BY c.catid;
別の解決策は、それほど効率的ではありませんが、エラーが発生した理由を説明するために表示します。
SELECT c.catname, COUNT(m.catid) AS item_count,
SUM(i.ownerid = @ownerid) AS owner_item_count
FROM categories c
LEFT JOIN map m USING (catid)
LEFT JOIN items i USING (itemid)
GROUP BY c.catid
HAVING item_count > 0;
WHERE
句の列エイリアスは、select-listの式の前に評価されるため、GROUP BY
句では使用できません。つまり、選択リスト式に関連付けられた値はまだ使用できません。
HAVING
、ORDER BY
、および<=>句で列エイリアスを使用できます。これらの句は、選択リスト内のすべての式が評価された後に実行されます。
他のヒント
SUM()内にCASEステートメントを忍び込ませることができます:
SELECT categories.catName,
COUNT(map.itemId) AS item_count,
SUM(CASE WHEN owner= @ownerid THEN 1 ELSE 0 END) AS owner_item_count
FROM categories
LEFT JOIN map ON categories.catId = map.catId
LEFT JOIN items ON items.itemId = map.itemId
GROUP BY categories.catId
HAVING COUNT(map.itemId) > 0
SELECT categories.catName,
COUNT(map.itemId) AS item_count,
COUNT(items.itemId) AS owner_item_count
FROM categories
INNER JOIN map
ON categories.catId = map.catId
LEFT JOIN items
ON items.itemId = map.itemId
AND items.owner = @ownerId
GROUP BY categories.catId
HAVING
でowner_item_count
句を使用できますが、内部結合がitem_countを処理することに注意してください。