SQL Server:按分组列求和并按另一列排序
Posted
技术标签:
【中文标题】SQL Server:按分组列求和并按另一列排序【英文标题】:SQL Server: SUM by grouped column and sort by another column 【发布时间】:2019-11-13 22:28:29 【问题描述】:我想将所有类似 Locations (name) 和 SUM the Volume (vol) 的位置结合起来,并在此处按月份排序结果。我试图选择一个子集并内部加入像这里这样的值,但不断得到分组而不是聚合子句错误,感谢提示! 结果应按月份排序,同一天同一位置的行应汇总在一行而不是多行。 这是我的选择语句,没有分组或求和:
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
当前结果: 按月中的某天排序,当天的相同位置不会汇总在一行中。
期望的结果: 按月中的某天排序,当天的相同位置汇总在一行中。 我也在汇总每天的总成交量和运行日期,但在 s-s-rS 中这样做。
我正在尝试 this 这样的解决方案
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
当我运行 proc 我得到 p>
消息 8120,级别 16,状态 1,过程 DailyLoadReportMTD,第 78 行 [批处理开始行 109] 列“#RECORDS.cmp_id”在选择列表中无效,因为它既不包含在聚合函数中,也不包含在 GROUP BY 子句中。
好的,Erics 的回答让我如此接近!只需要消除欺骗如果我 GROUP BY r.cmp_name, r.ord_revtype2, r.day_of_month 我必须添加 r.ofr_BSWheight 这会强制重复行...或抛出无效的选择错误 w/o
【问题讨论】:
请向我们展示示例数据和预期结果(作为表格文本)以澄清您的问题。 我在您发布的代码中没有看到,这会导致您提到的错误。 @Eric 感谢更新! 所有那些非聚合列都不在GROUP BY
中。因此错误。
在外部查询中,您按cmp_name
对记录进行分组。那么,如果您有多个记录具有相同的cmp_name
,但不同的run_ticket
或ord_rev
,会发生什么情况。在这种情况下会选择哪一个?
【参考方案1】:
问题描述引出了“which day_of_month do you want to order by”的问题。
由于您在name
上进行分组以获得vol
的总和,因此可以公平地假设每个name
会有多个R
,每个day_of_month
值可能不同.
不会导致“非聚合”错误的可能有效排序表达式是 ORDER BY MIN(day_of_month)
或 ORDER BY MAX(day_of_month)
.... 您甚至可以使用 AVG 或 SUM,但这些没有多大意义。
另外,'
是字符串分隔符,而不是标识符分隔符。在 MSSQL 中,您使用 ansi 标准 "
或特定于 MS 的 [
和 ]
。
【讨论】:
结果应按月份排序,同一天的同一位置应在一行而不是多行上求和。 @RayKoren 听起来你应该按位置和 day_of_month 分组。 抱歉没那么简单【参考方案2】:由于您想要所有这些列,因此窗口功能可能会更好。这行得通吗?
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
由于您删除了几列,简单的GROUP BY
应该可以工作。
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
【讨论】:
抱歉,这将返回整个日期范围内该位置的总和。就像每个租约仍然有多条线路,只是每条线路上的整个运行的总和 我在分区中添加了day_of_month
。
更接近,卷是正确的,只需要以某种方式删除重复的行!
如果run_ticket
、ticketdate
、ord_rev
有多个值,你会选择哪一个?
按 ord_rev 删除运行票和票日期和子组 查看更新的问题!谢谢!【参考方案3】:
我使用另一个临时表和 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
【讨论】:
以上是关于SQL Server:按分组列求和并按另一列排序的主要内容,如果未能解决你的问题,请参考以下文章