2013-04-30 10 views
7

Sto cercando di capire come restituire i primi 10 record per ogni gruppo di Trans.TranSID.t-SQL per trovare i primi 10 record per ogni gruppo

SELECT a.ABID, a.ABName, t.TranSID, SUM(IIF(TranTypeID = 'CO', td.Qty * CAST(td.Price AS money) * - 1, 
         td.Qty * CAST(td.Price AS money))) AS TotalSales 
FROM   Trans t INNER JOIN 
         TransDetail td ON t.TranID = td.TranID INNER JOIN 
         ABook a ON t.TranABID = a.ABID 
WHERE  (t.TranDate BETWEEN CONVERT(DATETIME, '2012-01-01 00:00:00', 102) AND CONVERT(DATETIME, '2013-01-01 00:00:00', 102)) AND 
      t.TranTypeID in ('SO','CA','CO') AND (t.TranStatus <> 'V') 
GROUP BY a.ABID, a.ABName, t.TranSID 
HAVING (NOT (a.ABName LIKE '%cash%')) 
ORDER BY t.TranSID, TotalSales Desc 

posso aggiungere "TOP 10" per l'istruzione select, ma che mi dà i primi 10 account indipendentemente dal gruppo. Ci sono 25 gruppi di Trans.TranSID e sto cercando di ottenere i primi 10 solo per ogni gruppo.

+0

L'inclusione di una struttura di tabella di base e dell'output atteso consente di ottenere risposte. – jTC

+0

Fondamentalmente vi è una tabella di conti cliente (Abook) e transazioni (Trans) e dettagli di transazione (TransDetail) tabelle. Struttura molto semplice. Desidera semplicemente sommare le vendite per ciascun cliente e raggruppare i primi 10 risultati per TranSID (che è il luogo in cui è avvenuta la transazione). –

risposta

10

Penso che tu sia alla ricerca di ROW_NUMBER() con un PARTITION BY

SELECT * 
FROM (
    SELECT 
     ROW_NUMBER() OVER(PARTITION BY t.TranSID ORDER BY t.TranSID, SUM(IIF(TranTypeID = 'CO', td.Qty * CAST(td.Price AS money) * - 1, td.Qty * CAST(td.Price AS money))) DESC) as RowNum,    
     a.ABID, 
     a.ABName, 
     t.TranSID, 
     SUM(IIF(TranTypeID = 'CO', td.Qty * CAST(td.Price AS money) * - 1, td.Qty * CAST(td.Price AS money))) AS TotalSales 
    FROM Trans t 
     INNER JOIN TransDetail td 
      ON t.TranID = td.TranID 
     INNER JOIN ABook a 
      ON t.TranABID = a.ABID 
    WHERE (t.TranDate BETWEEN CONVERT(DATETIME, '2012-01-01 00:00:00', 102) AND CONVERT(DATETIME, '2013-01-01 00:00:00', 102)) 
     AND t.TranTypeID in ('SO','CA','CO') 
     AND (t.TranStatus <> 'V') 
    GROUP BY a.ABID, a.ABName, t.TranSID 
    HAVING (NOT (a.ABName LIKE '%cash%')) 
) a 
WHERE a.RowNum <=10 

Questo assegnerà un numero di riga per ogni record nel raggruppamento (la colonna definita dalla PARTITION, che va da 1 a n. Da lì, è possibile eseguire un SELECT per afferrare qualsiasi numero di record per gruppo.

+0

Viene visualizzato il seguente messaggio di errore quando si esegue quel codice. Messaggio 1033, livello 15, stato 1, riga 20 La clausola ORDER BY non è valida per le viste, le funzioni inline, le tabelle derivate, le sottoquery e le espressioni di tabella comuni, a meno che non sia specificato anche TOP, OFFSET o FOR XML. –

+0

@GaryGerson, ho aggiornato il mio script. Prova a rimuovere il tasto 'ORDER BY' nella parte inferiore della subquery – valverij

+0

Sì, l'hai capito. L'ho effettivamente elaborato nello stesso momento in cui lo eri. –

1

Non ho molta familiarità con t-sql in particolare e sfortunatamente non ho accesso a un database t-sql per testare che questo compia il tuo obiettivo.

Detto questo, penso che questo sia un modo in cui è possibile ottenerlo utilizzando una sottoquery e la funzione ROW_NUMBER.

SELECT 
    * 
FROM (
    SELECT 
     a.ABID 
     , a.ABName 
     , t.TranSID 
     , SUM(IFF(TranTypeID = 'CO' 
      , td.Qty * CAST(td.Price AS MONEY) * -1 
      , td.Qty * CAST(td.Price AS MONEY))) AS TotalSales 
     , ROW_NUMBER() 
      OVER(PARTITION BY t.TranSID 
       ORDER BY SUM(IFF(TranTypeID = 'CO' 
        , td.Qty * CAST(td.Price AS MONEY) * -1 
        , td.Qty * CAST(td.Price AS MONEY))) DESC) AS row 
    FROM 
     Trans t 
     INNER JOIN TransDetail td 
     ON t.TranID = td.TranID 

     INNER JOIN ABook a 
     ON t.TranABID = a.ABID 

    WHERE 
     (t.TranDate BETWEEN CONVERT(DATETIME, '2012-01-01 00:00:00', 102) AND CONVERT(DATETIME, '2013-01-01 00:00:00', 102)) 
     AND t.TranTypeID in ('SO','CA','CO') 
     AND (t.TranStatus <> 'V') 

    GROUP BY 
     a.ABID 
     , a.ABName 
     , t.TranSID 

    HAVING 
     (NOT (a.ABName LIKE '%cash%')) 
) q 

WHERE 
    q.row <= 10 
+0

Come sopra, ricevo il seguente messaggio di errore quando eseguo questo. Messaggio 1033, livello 15, stato 1, riga 20 La clausola ORDER BY non è valida per le viste, le funzioni inline, le tabelle derivate, le sottoquery e le espressioni di tabella comuni, a meno che non sia specificato anche TOP, OFFSET o FOR XML. –

+1

Credo che il problema con la prima versione fosse che il campo ROW_NUMBER() aveva "AS TotalSales" all'interno della funzione somma. Quello che hai ora funziona. –

Problemi correlati