Abfrage: zählen mehrere Aggregate pro Artikel
-
07-07-2019 - |
Frage
Oft müssen Sie jedes Element eine Liste der Datenbankelemente und bestimmten aggregierten Zahlen zeigen. Zum Beispiel, wenn Sie den Titeltext auf Stack-Überlauf eingeben, wird die Verwandte Fragen Liste. Die Liste zeigt den Titel der entsprechenden Einträge und die einzelne aggregierten Anzahl der Anzahl der Antworten für jeden Titel.
Ich habe ein ähnliches Problem, sondern benötigen mehrere Aggregate. Ich möchte eine Liste der Elemente in einem 3 Formaten angezeigt werden, je nach Benutzeroptionen:
- My Name des Elements (15 insgesamt, 13 von mir gehört)
- My Name des Elements (15 insgesamt)
- Name meines Artikels (13 von mir gehört)
Meine Datenbank ist:
- Elemente : itemId, itemName, ownerId
- Kategorien : catId, catName
- Karte : mapId, itemId, catId
Die Abfrage unten bekommt: Kategorienamen, Anzahl der Artikel-IDs pro Kategorie
SELECT
categories.catName,
COUNT(map.itemId) AS item_count
FROM categories
LEFT JOIN map
ON categories.catId = map.catId
GROUP BY categories.catName
Diese erhält man: Kategorienamen, Anzahl der Artikel-IDs pro Kategorie für diese OWNER_ID nur
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
Aber wie ich sie in einer einzigen Abfrage zur gleichen Zeit bekommen? D.h .: Kategorienamen, Anzahl der Artikel-IDs pro Kategorie, Anzahl der Artikel-IDs pro Kategorie für diese OWNER_ID nur
Bonus. Wie kann ich abrufen optional nur dort, wo catID zählen! = 0 für alle diese? Bei dem Versuch, "WHERE ITEM_COUNT <> 0" erhalte ich:
MySQL said: Documentation
#1054 - Unknown column 'rid_count' in 'where clause'
Lösung
Hier ist ein Trick: eine SUM()
von Werten berechnen, die dafür bekannt sind, entweder 1 oder 0 entspricht einer COUNT()
der Zeilen, in denen der Wert 1 ist und Sie wissen, dass ein boolean Vergleich gibt 1 oder 0 (oder 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;
Wie für die Bonus-Frage, könnten Sie einfach tun eine innere Verknüpfung statt einer äußeren Verknüpfung, die nur Kategorien bedeuten würde, mit mindestens einer Reihe in map
zurückgegeben werden würde.
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;
Hier ist eine andere Lösung, die nicht so effizient ist, aber ich werde zeigen, es zu erklären, warum Sie die Fehlermeldung anzeigt:
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;
Sie können nicht Spalte Aliase in der WHERE
Klausel, weil Ausdrücke in der WHERE
Klausel verwenden, bevor die Ausdrücke in der Auswahlliste ausgewertet werden. Mit anderen Worten, assoziierten die Werte mit Select-Liste Ausdrücke noch nicht verfügbar ist.
Sie können Spaltenaliasnamen in den GROUP BY
, HAVING
und ORDER BY
Klauseln verwenden. Diese Klauseln werden ausgeführt, nachdem alle Ausdrücke in der Auswahlliste ausgewertet wurden.
Andere Tipps
Sie können eine CASE-Anweisung in Ihrem SUM schleichen ():
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
Beachten Sie, dass Sie eine HAVING
Klausel auf owner_item_count
verwenden könnte, aber die innere Verknüpfung kümmert sich um ITEM_COUNT für Sie.