问题
I'd like to combine all like Locations (name) and SUM the Volume (vol) for that location and order the results by Day of Month here. I attempted to Select a subset and inner join the values like here but kept getting group by not in aggregate clause errors, thank for the hints!! Results should be ordered by day of month and lines with the same location on same day should be summed on one line instead of multiple lines. Here is my Select Statement without grouping or summing:
SELECT
day_of_month AS 'Day of Month',
run_ticket AS 'Ticket number',
ticketdate AS 'Ticket Date',
id AS 'location id',
name AS 'location',
vol AS 'Volume',
ord_rev AS 'OrderHeader'
FROM
#RECORDS R
ORDER BY
day_of_month
Current Results: Ordered by day of month, same locations for that day are not summed on one line.
Desired Result: Ordered by day of month, same locations for that day are summed on one line. I am also summing total vol per day and for the dates run but doing that in SSRS.
I was trying this solution as such
SELECT day_of_month AS 'Day of Month'
,run_ticket AS 'Ticket Number'
,ticketdate AS 'Ticket Date'
,r2.cmp_id AS 'Location ID'
,cmp_name AS 'location'
,SUM(vol) AS 'Volume'
,ord_rev AS 'OrderHeader'
FROM #RECORDS as r2
JOIN
(SELECT cmp_id, SUM(vol) AS 'Volume'
FROM #RECORDS
GROUP BY cmp_name
) AS s ON s.cmp_id = r2.cmp_id
GROUP BY r2.cmp_name
ORDER BY day_of_month
When I run the proc I get
Msg 8120, Level 16, State 1, Procedure DailyLoadReportMTD, Line 78 [Batch Start Line 109] Column '#RECORDS.cmp_id' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
ok, Erics answer got me this close! just need to eliminate dupes If I GROUP BY r.cmp_name, r.ord_revtype2, r.day_of_month I had to add r.ofr_BSWheight which forces a duplicate line... or throws the invalid select error w/o it
回答1:
The problem description begs the question "which day_of_month do you want to order by".
Since you are grouping on name to get a sum of vol, it is fair to assume that there will be more than one R per name, each of which could have different day_of_month values.
Possible valid ordering expressions that would not result in "not in aggregate" errors are ORDER BY MIN(day_of_month) or ORDER BY MAX(day_of_month).... you could even use AVG or SUM, but those wouldn't make much sense.
Also, ' is a string delimiter, not an identifier delimiter. In MSSQL you use the ansi standard " or the MS-specific [ and ].
回答2:
I figured it out using another temp table and CTE
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
IF OBJECT_ID('tempdb..#RECORDS') IS NOT NULL
BEGIN
DROP TABLE #RECORDS
END
IF OBJECT_ID('tempdb..#RECORDS2') IS NOT NULL
BEGIN
DROP TABLE #RECORDS2
END
-- Insert statements for procedure here
CREATE TABLE #RECORDS
(
day_of_month int
--,run_ticket varchar(255)
,inv_seal_ondate datetime
,cmp_id varchar(255)
,cmp_name varchar(255)
,ofr_BSWHeight decimal
,ord_revtype2 varchar(255)
)
CREATE TABLE #RECORDS2
(
day_of_month int
--,run_ticket varchar(255)
,inv_seal_ondate datetime
,cmp_id varchar(255)
,cmp_name varchar(255)
,ofr_BSWHeight decimal
,ord_revtype2 varchar(255)
)
-- Initial population of Records temp table ------------------
INSERT INTO #RECORDS
( day_of_month
--,run_ticket
,inv_seal_ondate
,cmp_id
,cmp_name
,ofr_BSWHeight
,ord_revtype2
)
SELECT
(SELECT DAY(inv_seal_ondate)) --day_of_month extracted from inv_seal_ondate
--,o.run_ticket
,o.inv_seal_ondate
,c.cmp_id
,c.cmp_name
,o.ofr_BSWHeight
,oh.ord_revtype2
FROM OFR o
INNER JOIN company c on o.cmp_id = c.cmp_id
INNER JOIN orderhead oh on oh.ord_hdrnumber = o.ord_hdrnumber
WHERE o.inv_seal_ondate between @StartDate and @EndDate
AND c.cmp_altid in (@Company_AltId)
AND oh.ord_revtype2 in (@RevType2)
INSERT INTO #RECORDS2
( day_of_month
--,run_ticket
,inv_seal_ondate
,cmp_id
,cmp_name
,ofr_BSWHeight
,ord_revtype2
)
SELECT
day_of_month AS 'Day of Month'
--,run_ticket AS 'Run Ticket'
,inv_seal_ondate AS 'Ticket Date'
,cmp_id AS 'Lease ID'
,cmp_name AS 'Lease Name'
,SUM(ofr_BSWHeight) OVER(PARTITION BY day_of_month , cmp_name) AS 'NSV'
,ord_revtype2 AS 'OrderHeaderRevType2'
FROM #RECORDS r
ORDER BY day_of_month
;WITH cte AS (
Select
day_of_month
,inv_seal_ondate
,cmp_name
,ofr_BSWHeight
,ord_revtype2
,ROW_NUMBER() OVER (
PARTITION BY
day_of_month
,cmp_name
ORDER BY
day_of_month
) row_num
FROM
#RECORDS2
)
DELETE FROM cte
WHERE row_num > 1;
-------------- Return Primary Result Set ----------------------------
SELECT
day_of_month AS 'Day of Month'
--,run_ticket AS 'Run Ticket'
,inv_seal_ondate AS 'Ticket Date'
,cmp_id AS 'Lease ID'
,cmp_name AS 'Lease Name'
,ofr_BSWHeight AS 'NSV'
,ord_revtype2 AS 'OrderHeaderRevType2'
FROM #RECORDS2 r2
ORDER BY day_of_month
END
回答3:
SELECT
day_of_month AS 'Day of Month'
,run_ticket AS 'Ticket number'
,ticketdate AS 'Ticket Date'
,id AS 'location id'
,name AS 'location'
,(SUM)vol AS 'Volume'
,ord_rev AS 'OrderHeader'
FROM #RECORDS,R
ORDER BY day_of_month
Aggrergate functions only use in SELECT clause I understand you just want to display sum of volume so you need to add (SUM)vol.
回答4:
Since you want all those columns, probably window function will work better. Will this work?
SELECT day_of_month AS 'Day of Month'
, run_ticket AS 'Ticket Number'
, ticketdate AS 'Ticket Date'
, cmp_id AS 'Location ID'
, cmp_name AS 'location'
, SUM(vol) OVER(PARTITION BY day_of_month, cmp_name) AS 'Volume'
, ord_rev AS 'OrderHeader'
FROM #RECORDS
Since you remove a few columns, simple GROUP BY should work.
SELECT day_of_month AS 'Day of Month'
, cmp_id AS 'Location ID'
, cmp_name AS 'location'
, SUM(vol) AS 'Volume'
, ord_rev AS 'OrderHeader'
FROM #RECORDS
GROUP BY day_of_month, cmp_id, cmp_name, ord_rev
来源:https://stackoverflow.com/questions/58846598/sql-server-sum-by-grouped-column-and-sort-by-another-column