2016-04-12 13 views
0

Ich versuche, eine bestimmte Spalte über einen bestimmten Zeitraum zu summieren. Der Kicker ist, dass ich möchte, dass dies ein CTE ist, weil ich es mehrmals als Teil einer größeren Abfrage verwenden muss. Da es ein CTE ist, muss es die Datumsspalte sowie die Summen- und ID-Spalten haben, was bedeutet, dass ich nach Datum UND ID gruppieren muss. Das führt dazu, dass meine Ergebnisse nach ID und Datum gruppiert werden, sodass mir keine einzige Summe über den Zeitraum zur Verfügung steht, sondern eine Menge an Summen, eine für jeden Tag.Summieren einer Spalte über einen Datumsbereich in einem CTE?

es einfach zu machen, sagen wir:

create table orders ( 
id int primary key, 
itemID int foreign key references items.id, 
datePlaced datetime, 
salesRep int foreign key references salesReps.id, 
price int, 
amountShipped int); 

Jetzt haben wir das Gesamtgeld eine bestimmte Vertriebsmitarbeiter, die während eines Geschäftsjahres, aufgeschlüsselt nach Artikel erhalten möchten. Das heißt, das Geschäftsjahrjahr ignorierend:

select itemName, sum(price) as totalSales, sum(totalShipped) as totalShipped 
from orders 
join items on items.id = orders.itemID 
where orders.salesRep = '1234' 
group by itemName 

Einfach genug. Aber wenn Sie noch etwas hinzufügen, sogar den Preis, spuckt die Abfrage viel mehr Zeilen aus, als Sie wollten.

select itemName, price, sum(price) as totalSales, sum(totalShipped) as totalShipped 
    from orders 
join items on items.id = orders.itemID 
where orders.salesRep = '1234' 
group by itemName, price 

Jetzt ist jede Gruppe (Name, Preis) statt nur (Name). Dies ist eine Art von Sudocode, aber in meiner Datenbank bewirkt nur diese Änderung, dass meine Ergebnismenge von 13 auf 32 Zeilen springt. Hinzu kommt, dass der Datumsbereich, und Sie wirklich ein Problem haben:

select itemName, price, sum(price) as totalSales, sum(totalShipped) as totalShipped 
from orders 
join items on items.id = orders.itemID 
where orders.salesRep = '1234' 
    and orderDate between 150101 and 151231 
group by itemName, price 

Dieses auf das letzte Beispiel identisch ist. Das Problem ist, so dass es ein CTE:

with totals as ( 
select itemName, price, sum(price) as totalSales, sum(totalShipped) as totalShipped, orderDate as startDate, orderDate as endDate 
    from orders 
    join items on items.id = orders.itemID 
    where orders.salesRep = '1234' 
    and orderDate between startDate and endDate 
group by itemName, price, startDate, endDate 
) 
select totals_2015.itemName as itemName_2015, totals_2015.price as price_2015, ... 
totals_2016.itemName as itemName_2016, ... 
from ( 
select * from totals 
where startDate = 150101 and endDate = 151231 
) totals_2015 
join ( 
select * 
from totals 
where startDate = 160101 and endDate = 160412 
) totals_2016 
on totals_2015.itemName = totals_2016.itemName 

Nun ist die Gruppierung in der CTE ist, ist unter mehr als das Hinzufügen der Preis es geschafft. Ich habe darüber nachgedacht, die Preisanfrage innerhalb des CTE in eine eigene Unterabfrage zu zerlegen, aber ich kann mir nicht entgehen lassen, nach den Daten gruppieren zu müssen, um den Datumsbereich zu erhalten. Kann jemand einen Weg da rum sehen? Ich hoffe, ich habe die Dinge klar genug gemacht. Dies wird auf einem IBM iSeries-Computer ausgeführt. Vielen Dank!

+0

Warum denkst du 'Da es ein CTE ist, muss es die Datumsspalte haben 'ist wahr? –

+0

Sorry, das habe ich nicht klargestellt. Der CTE wird verwendet, um mehrere Jahre zu erhalten, wie im letzten Beispiel. Auf diese Weise kann das gleiche CTE verwendet werden, um zwei, drei, vier oder mehr Jahre zu erhalten, indem einfach unterschiedliche Daten angegeben werden. Dies wird an eine Tabelle auf einer Website ausgegeben, mit einer Zeile pro Elementname und so vielen Spalten wie Jahren, multipliziert mit der Anzahl von (Preis, Gesamtversand, Gesamtumsatz). – AH16

+0

Vielleicht ist eine temporäre Tabelle oder Sichtweise ein besserer Ansatz als eine CTE. Übrigens erhalten Sie eher Hilfe, wenn Sie sich die Mühe machen, Ihre Frage richtig zu formatieren, dh Ihren Code als Code zu formatieren. –

Antwort

0

ich schließlich eine Lösung gefunden, und es ist kein CTE überhaupt benötigen. Ich wollte, dass das CTE Code-Duplikation vermeidet, aber das funktioniert fast genauso gut. Hier ist eine thread explaining summing conditionally, die genau das tut, was ich gesucht habe.

0

Je nachdem, was Sie suchen, könnte dies ein besserer Ansatz sein:

select 'by sales rep' breakdown 
, salesRep 
, '' year 
, sum(price * amountShipped) amount 
from etc 
group by salesRep 

union 

select 'by sales rep and year' breakdown 
, salesRep 
, convert(char(4),orderDate, 120) year 
, sum(price * amountShipped) amount 
from etc 
group by salesRep, convert(char(4),orderDate, 120) 

etc 
+0

Sorry, aber ich folge dem Beispiel nicht. Wie würde ich die Summe auf einen bestimmten Datumsbereich beschränken, und würde dies nicht zu doppelten Zeilen führen? Oder mindestens zwei Zeilen pro Ergebnis? – AH16

0

Wenn möglich Gruppe durch die ID-Spalten oder Fremdschlüssel, da die Spalten indiziert sind bereits werden Sie schneller Ergebnisse zu erzielen. Dies gilt für jede Datenbank.

with cte as (
select id,rep, sum(sales) sls, count(distinct itemid) did, count(*) cnt from sommewhere 
where date between x and y 
group by id,rep 
) select * from cte order by rep 

oder mehr Phantasie

with cte as (
select id,rep, sum(sales) sls, count(distinct itemid) did, count(*) cnt from sommewhere 
where date between x and y 
group by id,rep 
) select * from cte join reps on cte.rep = reps.rep order by sls desc 
+0

Danke für die Antwort, aber Sie haben die Daten im CTE hart codiert. Mein Problem ist, dass ich den CTE verwenden kann, um diese Beträge zwischen zwei Daten zu erhalten. Das bedeutet, dass zwei Datumsspalten in die Auswahl eingefügt werden müssen, da der CTE nur Datumsangaben erhalten kann, indem Daten ausgewählt werden, und das bedeutet Gruppierung nach Datum. Es sei denn, ich habe etwas schlecht verstanden (sehr wahrscheinlich). – AH16

+0

Sie geben zur Laufzeit x und y ein Sie können nach ID, rep, Jahr (Datum), Monat (Datum) im CTE-Block gruppieren. Geh dafür, du kannst es tun. Denken Sie jedoch immer an die Gruppe, die über einen Schlüssel verfügt, der als erstes Element in der Klausel group by aufgebaut ist, und Ihre Abfragen werden schnell ausgeführt. – danny117

+0

Ich verwende ein CTE, um die Anpassung zur Laufzeit zu vermeiden. Zum Beispiel möchte ich es zweimal aufrufen, einmal für einen Datumsbereich und wieder für einen anderen. Dies könnte dazu führen, dass eine Webseite bereitgestellt wird, sodass die Daten aus einem Formular stammen müssen. Die Verwendung eines Formulars wäre einfach, da ich die Werte einfach ersetzen könnte, aber ich konnte es immer noch nicht mehr als einmal verwenden. – AH16