Selecteer meerdere kolommen uit een tabel, maar groepeer ze op één

De tabelnaam is “OrderDetails” en de kolommen worden hieronder gegeven:

OrderDetailID || ProductID || ProductName || OrderQuantity

Ik probeer meerdere kolommen te selecteren en te groeperen op product-ID terwijl ik SUM of OrderQuantity heb.

Select ProductID,ProductName,OrderQuantity Sum(OrderQuantity)
 from OrderDetails Group By ProductID

Maar deze code geeft natuurlijk een foutmelding. Ik moet andere kolomnamen toevoegen om te groeperen op, maar dat is niet wat ik wil en aangezien mijn gegevens veel items bevatten, zijn resultaten op die manier onverwacht.

Voorbeeldgegevensquery:

ProductID,ProductName,OrderQuantity van OrderDetails

Resultaten staan ​​hieronder:

ProductID     ProductName    OrderQuantity
    1001          abc               5
    1002          abc               23    (ProductNames can be same)
    2002          xyz               8
    3004          ytp               15
    4001          aze               19
    1001          abc               7     (2nd row of same ProductID)

Verwacht resultaat:

ProductID     ProductName    OrderQuantity
    1001          abc               12    (group by productID while summing)
    1002          abc               23
    2002          xyz               8
    3004          ytp               15
    4001          aze               19

Hoe selecteer ik meerdere kolommen en de kolom Groeperen op ProductID, aangezien ProductName niet uniek is?

Terwijl u dat doet, krijgt u ook de som van de kolom OrderQuantity.


Antwoord 1, autoriteit 100%

Ik gebruik deze truc om op één kolom te groeperen als ik een selectie met meerdere kolommen heb:

SELECT MAX(id) AS id,
    Nume,
    MAX(intrare) AS intrare,
    MAX(iesire) AS iesire,
    MAX(intrare-iesire) AS stoc,
    MAX(data) AS data
FROM Produse
GROUP BY Nume
ORDER BY Nume

Dit werkt.


Antwoord 2, autoriteit 8%

Uw gegevens

DECLARE @OrderDetails TABLE 
(ProductID INT,ProductName VARCHAR(10), OrderQuantity INT)
INSERT INTO @OrderDetails VALUES
(1001,'abc',5),(1002,'abc',23),(2002,'xyz',8),
(3004,'ytp',15),(4001,'aze',19),(1001,'abc',7)

Query

Select ProductID, ProductName, Sum(OrderQuantity) AS Total
 from @OrderDetails 
 Group By ProductID, ProductName  ORDER BY ProductID

Resultaat

╔═══════════╦═════════════╦═══════╗
║ ProductID ║ ProductName ║ Total ║
╠═══════════╬═════════════╬═══════╣
║      1001 ║ abc         ║    12 ║
║      1002 ║ abc         ║    23 ║
║      2002 ║ xyz         ║     8 ║
║      3004 ║ ytp         ║    15 ║
║      4001 ║ aze         ║    19 ║
╚═══════════╩═════════════╩═══════╝

Antwoord 3, autoriteit 8%

Ik wilde alleen een effectievere en algemenere manier toevoegen om dit soort problemen op te lossen.
Het belangrijkste idee gaat over het werken met subquery’s.

doe je groep op en sluit je aan bij dezelfde tafel op de ID van de tafel.

uw geval is specifieker omdat uw product-ID niet uniekis, dus er zijn 2 manieren om dit op te lossen.

Ik zal beginnen met de meer specifieke oplossing:
Aangezien uw product-ID niet uniekis, hebben we een extra stap nodig, namelijk het selecteren van DISCTINCTproduct-ID’s na het groeperen en het uitvoeren van de subquery als volgt:

WITH CTE_TEST AS (SELECT productId, SUM(OrderQuantity) Total
                    FROM OrderDetails
                    GROUP BY productId)
SELECT DISTINCT(OrderDetails.ProductID), OrderDetails.ProductName, CTE_TEST.Total
FROM OrderDetails 
INNER JOIN CTE_TEST ON CTE_TEST.ProductID = OrderDetails.ProductID

dit levert precies op wat er wordt verwacht

ProductID     ProductName         Total
    1001          abc               12    
    1002          abc               23
    2002          xyz               8
    3004          ytp               15
    4001          aze               19

Maarer is een schonere manier om dit te doen. Ik denk dat ProductIdeen refererende sleutel is voor de producttabel en ik denk dat er een OrderIdprimaire sleutel(uniek) in deze tabel moet staan.

in dit geval hoeft u maar een paar stappen te ondernemen om extra kolommen op te nemen terwijl u op slechts één kolommen groepeert. Het zal dezelfde oplossing zijn als de volgende

Laten we deze t_Valuetabel als voorbeeld nemen:

voer hier de afbeeldingsbeschrijving in

Als ik wil groeperen op beschrijving en ook alle kolommen wil weergeven.

Het enige wat ik hoef te doen is:

  1. maak WITH CTE_Namesubquery met uw GroupBy-kolom en COUNT-voorwaarde
  2. selecteer alles (of wat u ook wilt weergeven) uit de waardetabel en het totaal uit de CTE
  3. INNER JOINmet CTE in de kolom ID(primaire sleutel of unieke beperking)

en dat is het!

Hier is de vraag

WITH CTE_TEST AS (SELECT Description, MAX(Id) specID, COUNT(Description) quantity 
                    FROM sch_dta.t_value
                    GROUP BY Description)
SELECT sch_dta.t_Value.*, CTE_TEST.quantity 
FROM sch_dta.t_Value 
INNER JOIN CTE_TEST ON CTE_TEST.specID = sch_dta.t_Value.Id

En hier is het resultaat:

voer hier de afbeeldingsbeschrijving in


Antwoord 4, autoriteit 3%

mysqlGROUP_CONCAT-functie kan https://dev.mysql.com/doc/refman/8.0/en/group-by-functions.html#function_group-concat

SELECT ProductID, GROUP_CONCAT(DISTINCT ProductName) as Names, SUM(OrderQuantity)
FROM OrderDetails GROUP BY ProductID

Dit zou terugkeren:

ProductID     Names          OrderQuantity
1001          red            5
1002          red,black      6
1003          orange         8
1004          black,orange   15

Vergelijkbaar idee als degene die @Urs Marian hier plaatste https://stackoverflow.com/a/38779277/906265


Antwoord 5, autoriteit 2%

   WITH CTE_SUM AS (
      SELECT ProductID, Sum(OrderQuantity) AS TotalOrderQuantity 
      FROM OrderDetails GROUP BY ProductID
    )
    SELECT DISTINCT OrderDetails.ProductID, OrderDetails.ProductName, OrderDetails.OrderQuantity,CTE_SUM.TotalOrderQuantity 
    FROM 
    OrderDetails INNER JOIN CTE_SUM 
    ON OrderDetails.ProductID = CTE_SUM.ProductID

Controleer of dit werkt.


Antwoord 6, autoriteit 2%

Je kunt dit proberen:

Select ProductID,ProductName,Sum(OrderQuantity) 
 from OrderDetails Group By ProductID, ProductName

U hoeft alleen kolommen te Group Bydie geen statistische functie hebben in de Select-clausule. U kunt in dit geval dus gewoon Group ByProductID en ProductName gebruiken.


Antwoord 7, autoriteit 2%

U kunt de onderstaande zoekopdracht proberen. Ik neem aan dat je één tabel hebt voor al je gegevens.

SELECT OD.ProductID, OD.ProductName, CalQ.OrderQuantity
FROM (SELECT DISTINCT ProductID, ProductName
      FROM OrderDetails) OD
INNER JOIN (SELECT ProductID, OrderQuantity SUM(OrderQuantity)
            FROM OrderDetails
            GROUP BY ProductID) CalQ
ON CalQ.ProductID = OD.ProductID

Antwoord 8, autoriteit 2%

Naar mijn mening is dit een ernstige taalfout waardoor SQL lichtjaren achterloopt op andere talen. Dit is mijn ongelooflijk hacky-oplossing. Het is een hele klus, maar het werkt altijd.

Voordat ik dat doe, wil ik de aandacht vestigen op het antwoord van @Peter Mortensen, dat naar mijn mening het juiste antwoord is. De enige reden waarom ik in plaats daarvan het onderstaande doe, is omdat de meeste implementaties van SQL ongelooflijk trage join-bewerkingen hebben en je dwingen te breken “herhaal jezelf niet”. Ik wil dat mijn vragen snel worden ingevuld.

Dit is ook een oude manier om dingen te doen. STRING_AGGen STRING_SPLITzijn een stuk schoner. Nogmaals, ik doe het op deze manier omdat het altijd werkt.

-- remember Substring is 1 indexed, not 0 indexed
SELECT ProductId
  , SUBSTRING (
      MAX(enc.pnameANDoq), 1, CHARINDEX(';', MAX(enc.pnameANDoq)) - 1
    ) AS ProductName
  , SUM ( CAST ( SUBSTRING (
      MAX(enc.pnameAndoq), CHARINDEX(';', MAX(enc.pnameANDoq)) + 1, 9999
    ) AS INT ) ) AS OrderQuantity
FROM (
    SELECT CONCAT (ProductName, ';', CAST(OrderQuantity AS VARCHAR(10)))
      AS pnameANDoq, ProductID
    FROM OrderDetails
  ) enc
GROUP BY ProductId

Of in gewone taal:

  • Lijm alles behalve één veld samen tot een string met een scheidingsteken waarvan je weet dat het niet zal worden gebruikt
  • Gebruik subtekenreeks om de gegevens te extraheren nadat ze zijn gegroepeerd

Wat betreft prestaties Ik heb altijd superieure prestaties gehad door snaren te gebruiken in plaats van bijvoorbeeld bigints. Met microsoft en oracle is substring tenminste een snelle operatie.

Dit vermijdt de problemen die u tegenkomt wanneer u MAX() gebruikt, waarbij wanneer u MAX() op meerdere velden gebruikt, ze niet langer overeenkomen en uit verschillende rijen komen. In dit geval worden uw gegevens gegarandeerd precies zo aan elkaar gelijmd als u had gevraagd.

Om toegang te krijgen tot een 3e of 4e veld, heb je geneste substrings nodig, “zoek na de eerste puntkomma een 2e”. Daarom is STRING_SPLIT beter als het beschikbaar is.

Opmerking: Hoewel dit buiten het bestek van uw vraag valt, is dit vooral handig wanneer u zich in de tegenovergestelde situatie bevindt en u groepeert op een gecombineerde sleutel, maar niet wilt dat elke mogelijke permutatie wordt weergegeven, dat wil zeggen dat u ‘ wilt blootleggen ‘ foo’ en ‘bar’ als een gecombineerde sleutel maar wil groeperen op ‘foo’


Antwoord 9

==EDIT==

Ik heb je vraag opnieuw gecontroleerd en ben tot de conclusie gekomen dat dit niet kan.

Productnaam is niet uniek, het moet deel uitmaken van de Group Byof worden uitgesloten van uw resultaten.

Hoe zou SQL deze resultaten bijvoorbeeld aan u presenteren als u Group Byalleen ProductID?

ProductID | ProductName | OrderQuantity 
---------------------------------------
1234      | abc         | 1
1234      | def         | 1
1234      | ghi         | 1
1234      | jkl         | 1

Antwoord 10

Ik had een soortgelijk probleem als de OP. Toen zag ik het antwoord van @Urs Marian, wat veel heeft geholpen.
Maar daarnaast was ik op zoek naar, wanneer er meerdere waarden in een kolom zijn en ze worden gegroepeerd, hoe ik de laatst ingediende waarde kan krijgen (bijvoorbeeld gesorteerd op een datum/id-kolom).

Voorbeeld:

We hebben de volgende tabelstructuur:

CREATE TABLE tablename(
    [msgid] [int] NOT NULL,
    [userid] [int] NOT NULL,
    [username] [varchar](70) NOT NULL,
    [message] [varchar](5000) NOT NULL
) 

Er staan ​​nu minstens twee datasets in de tabel:

+-------+--------+----------+---------+
| msgid | userid | username | message |
+-------+--------+----------+---------+
|     1 |      1 | userA    | hello   |
|     2 |      1 | userB    | world   |
+-------+--------+----------+---------+

Daarom werkt het volgende SQL-script (aangevinkt op MSSQL) om het te groeperen, ook als hetzelfde gebruikers-ID verschillende gebruikersnaamwaarden heeft. In het onderstaande voorbeeld wordt de gebruikersnaam met de hoogste msgstr getoond:

SELECT m.userid, 
(select top 1 username from table where userid = m.userid order by msgid desc) as username,
count(*) as messages
FROM tablename m
GROUP BY m.userid
ORDER BY count(*) DESC

Antwoord 11

SELECT ProductID, ProductName, OrderQuantity, SUM(OrderQuantity) FROM OrderDetails WHERE(OrderQuantity) IN(SELECT SUM(OrderQuantity) FROM OrderDetails GROUP BY OrderDetails) GROUP BY ProductID, ProductName, OrderQuantity;

Ik heb de bovenstaande oplossing gebruikt om een ​​soortgelijk probleem in Oracle12c op te lossen.

Other episodes