2017-11-27 5 views
1

Guten Tag Leute, ich habe mit diesem für den letzten Tag gekämpft und ich kann einfach nicht scheinen, es herauszufinden.Holen Sie sich das meistverkaufte Produkt für jedes Land von NORTHWIND Datenbank

Meine Aufgabe ist es, die am meisten verkaufte Produkt für jedes Land von der beliebten Open-Source-Datenbank namens NORTH abzuleiten: https://northwinddatabase.codeplex.com

konnte mich auf diese Bühne bekommen, hier ist mein Code in SQL Server:

--Get most sold product for each country 
WITH TotalProductsSold AS 
(
    SELECT od.ProductID, SUM(od.Quantity) AS TotalSold 
     FROM [Order Details] AS od 
     GROUP BY od.ProductID 
) 
SELECT MAX(TotalProductsSold.TotalSold) AS MostSoldQuantity, s.Country --,p.ProductName 
    FROM Products AS p 
    INNER JOIN TotalProductsSold 
    ON TotalProductsSold.ProductID = p.ProductID 
    INNER JOIN Suppliers AS s 
    ON s.SupplierID = p.SupplierID 
    GROUP BY s.Country 
    ORDER BY MostSoldQuantity DESC 

das gibt mir das folgende Ergebnis:

enter image description here

das ist alles gut ist, aber ich wünschte, ou zu finden t Der Produktname für die MostSoldQuantity.

Vielen Dank!

PS Ich habe einen Kommentar --p.ProductName, wo ich dachte, es würde funktionieren, aber es nicht und wenn jemand mir erklären könnte, warum GROUP BY nicht automatisch erlauben, den Produktnamen für die Zeile abzuleiten, die großartig wäre

+0

Ich nehme an, Sie wissen, dass Ihre vorgeschlagene Antwort nicht funktioniert, wie Sie es gelöscht haben. Der wichtige * Grund * ist, dass die 'MAX (productID)' überhaupt nichts mit 'MAX (TotalSold)' zu tun hat, sie werden unabhängig voneinander berechnet. (Sie erstellen den Datensatz, Sie erstellen Gruppen innerhalb des Datensatzes, innerhalb jeder Gruppe erhalten Sie den höchsten TotalSold und separat erhalten Sie den höchsten Wert von ProductID. Es gibt keinen SQL-Ausdruck für * "ermitteln Sie die Produkt-ID, die dem zugeordnet ist." Ergebnis von 'MAX (TotalSold)' wie in einem anderen Ausdruck in der SELECT-Liste berechnet "*). – MatBailie

+0

Ja, ich habe festgestellt, sobald ich die Produkt-IDs nicht zu den meistverkauften Menge –

+0

Ich schaue auf Ihre Antwort jetzt, danke für Ihre Zeit :) –

Antwort

1

Beginnen Sie zuerst mit der Anzahl der verkauften Produkte pro Land, nicht nur pro Produkt. Dann sie Rang und nur etwas bei RANK = 1. So etwas wie ...

WITH 
    ProductQuantityByCountry AS 
(
    SELECT 
     s.CountryID, 
     p.ProductID, 
     SUM(od.Quantity) AS Quantity 
    FROM 
     [Order Details] AS od 
    INNER JOIN 
     Products   AS p 
      ON p.ProductID = od.ProductID 
    INNER JOIN 
     Suppliers   AS s 
      ON s.SupplierID = p.SupplierID 
    GROUP BY 
     s.CountryID, 
     p.ProductID 
), 
    RankedProductQuantityByCountry 
AS 
(
    SELECT 
     RANK() OVER (PARTITION BY CountryID ORDER BY Quantity DESC) AS countryRank, 
     * 
    FROM 
     ProductQuantityByCountry 
) 
SELECT 
    * 
FROM 
    RankedProductQuantityByCountry 
WHERE 
    countryRank = 1 

Hinweis zu holen, kann ein Land identisch Menge verschiedener producs liefern, und so zwei Produkte beide Rang haben könnte = 1. Suchen Sie in ROW_NUMER() und/oder DENSE_RANK() für andere, aber ähnliche Verhaltensweisen zu RANK().

EDIT: Ein einfaches obwohl abzudecken ausüben, warum SQL Sie setzen Product.Name in Ihrer letzten Abfrage nicht nachlässt ist es, eine Frage zu stellen.

Was sollte SQL in diesem Fall tun?

SELECT 
    MAX(TotalProductsSold.TotalSold) AS MostSoldQuantity, 
    MIN(TotalProductsSold.TotalSold) AS LeastSoldQuantity, 
    s.Country, 
    p.ProductName 
FROM 
    blahblahblah 
GROUP BY 
    s.Country 
ORDER BY 
    MostSoldQuantity DESC 

Die Anwesenheit eines MINund ein MAX macht die Sache nicht eindeutig.

Sie klar sein, dass Sie eine Operation by country und dass die Operation ausgeführt werden sollen aus diesem Land das Produkt mit dem höchsten Umsatzvolumen zu holen. Aber es ist nicht wirklich explizit, und kleine Änderungen an der Abfrage könnten sehr verwirrende Konsequenzen für jedes abgeleitete Verhalten haben. Stattdessen liefert die deklarative Syntax von SQL eine sehr klare/explizite/deterministische Beschreibung des zu lösenden Problems.

Wenn ein Ausdruck nicht in der GROUP BY -Klausel erwähnt wird, können Sie nicht SELECT es, ohne es zu aggregieren. Dies ist so, dass es keine Zweideutigkeit gibt, was gemeint ist oder was die SQL-Engine tun soll.

Durch die Sie auffordert, get the total sales per country per product auf einer Ebene der Abfrage festzulegen, können Sie dann sauber Zustand and then pick the highest ranked per country auf einer anderen Ebene der Abfrage.

Dies kann so sein, als ob Sie mit Abfragen enden, die länger sind als "sollte" notwendig sein. Es führt jedoch auch zu völlig unzweideutigen Abfragen, sowohl für das Kompilieren der Abfrage bis zu einem Ausführungsplan als auch für andere Programmierer, die Ihren Code in Zukunft lesen werden.

+0

Vielen Dank! Ich habe es zur Arbeit gebracht und ich habe deine Ideen benutzt. Ich bin noch ein Anfänger in SQL und ich wusste nicht über die Ranking-Funktionen und ich dachte, dass es eine einfachere Lösung sein muss, ohne über GROUP BY hinauszugehen und Funktionen zu aggregieren, aber bis jetzt ist deine Antwort die einzige, die mein Problem löst auf eine schlechte Art und Weise. Danke Mann! :) –

+0

Sie (wenn ich mich richtig erinnere) tun RANK() OVER (PARTITION von CountryID ORDER BY SUM (Menge) DESC) AS CountryRank im ersten CTE, um es zu kürzen, habe ich es einfach getrennt, um es für Sie klarer zu machen . – MatBailie

Verwandte Themen