Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/81.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 使用单个表中的分区对多个列求和_Sql_Sql Server_Join_Sum_Window Functions - Fatal编程技术网

Sql 使用单个表中的分区对多个列求和

Sql 使用单个表中的分区对多个列求和,sql,sql-server,join,sum,window-functions,Sql,Sql Server,Join,Sum,Window Functions,我有一个问题,看起来很简单,但我想不出来。 我有这样一个示例表: Overtime Table (OT) +----------+------------+----------+-------------+ |EmployeeId|OvertimeDate|HourMargin|OvertimePoint| +----------+------------+----------+-------------+ | 1| 2020-07-01| 05:00|

我有一个问题,看起来很简单,但我想不出来。 我有这样一个示例表:

Overtime Table (OT)
+----------+------------+----------+-------------+
|EmployeeId|OvertimeDate|HourMargin|OvertimePoint|
+----------+------------+----------+-------------+
|         1|  2020-07-01|     05:00|           15|
|         1|  2020-07-02|     03:00|            9|
|         2|  2020-07-01|     01:00|            3|
|         2|  2020-07-03|     03:00|            9|
|         3|  2020-07-06|     03:00|            9|
|         3|  2020-07-07|     01:00|            3|
+----------+------------+----------+-------------+

OLC Table (OLC)
+----------+------------+-----+------+
|EmployeeId|   OLCDate  | OLC | Trip |
+----------+------------+-----+------+
|         1|  2020-07-01|    2|     0|
|         3|  2020-07-13|    3|     6|
+----------+------------+-----+------+
Result
+----------+-----------+----------+--------+----------+
|EmployeeId|TotalMargin|TotalPoint|TotalOLC|TotalPoint|
+----------+-----------+----------+--------+----------+
|         1|      08:00|        24|       2|         0|
|         2|      04:00|        12|       0|         0|
|         3|      04:00|        24|       3|         6|
+----------+-----------+----------+--------+----------+
因此,根据这些表,我想计算总OT.HourMargin、OT.OTPoint、OLC.OLC和OLC.Trip,最终结果如下:

Overtime Table (OT)
+----------+------------+----------+-------------+
|EmployeeId|OvertimeDate|HourMargin|OvertimePoint|
+----------+------------+----------+-------------+
|         1|  2020-07-01|     05:00|           15|
|         1|  2020-07-02|     03:00|            9|
|         2|  2020-07-01|     01:00|            3|
|         2|  2020-07-03|     03:00|            9|
|         3|  2020-07-06|     03:00|            9|
|         3|  2020-07-07|     01:00|            3|
+----------+------------+----------+-------------+

OLC Table (OLC)
+----------+------------+-----+------+
|EmployeeId|   OLCDate  | OLC | Trip |
+----------+------------+-----+------+
|         1|  2020-07-01|    2|     0|
|         3|  2020-07-13|    3|     6|
+----------+------------+-----+------+
Result
+----------+-----------+----------+--------+----------+
|EmployeeId|TotalMargin|TotalPoint|TotalOLC|TotalPoint|
+----------+-----------+----------+--------+----------+
|         1|      08:00|        24|       2|         0|
|         2|      04:00|        12|       0|         0|
|         3|      04:00|        24|       3|         6|
+----------+-----------+----------+--------+----------+
以下是我试图获得结果的查询:

DECLARE @Overtime TABLE (
    EmployeeId      INT,
    OvertimeDate    DATE,
    HourMargin      TIME,
    OvertimePoint   INT
)

DECLARE @OLC TABLE (
    EmployeeId      INT,
    OLCDate         DATE,
    OLC             INT,
    Trip            INT
)

INSERT INTO @Overtime VALUES (1, '2020-07-01', '05:00:00', 15)
INSERT INTO @Overtime VALUES (1, '2020-07-02', '03:00:00', 9)
INSERT INTO @Overtime VALUES (2, '2020-07-01', '01:00:00', 3)
INSERT INTO @Overtime VALUES (2, '2020-07-03', '03:00:00', 9)
INSERT INTO @Overtime VALUES (3, '2020-07-06', '03:00:00', 9)
INSERT INTO @Overtime VALUES (3, '2020-07-07', '01:00:00', 3)

INSERT INTO @OLC VALUES (1, '2020-07-01', 2, 0)
INSERT INTO @OLC VALUES (3, '2020-07-13', 3, 6)

SELECT
    OT.EmployeeId,
    CONVERT(TIME, DATEADD(MS, (SUM(DATEDIFF(MS, '00:00:00.000', OT.HourMargin)) OVER (PARTITION BY OT.EmployeeId)), '00:00:00.000')) AS TotalMargin,
    SUM(OT.OvertimePoint) OVER (PARTITION BY OT.EmployeeId) AS TotalPoint,
    SUM(OLC.OLC) OVER (PARTITION BY OLC.EmployeeId) AS TotalOLC,
    SUM(OLC.Trip) OVER (PARTITION BY OLC.EmployeeId) AS TotalTrip
FROM
    @Overtime OT
    LEFT JOIN @OLC OLC ON OLC.EmployeeId = OT.EmployeeId
                          AND OLC.OLCDate = OT.OvertimeDate
ORDER BY
    EmployeeId
以下是我的查询结果:

+----------+-----------+----------+--------+----------+
|EmployeeId|TotalMargin|TotalPoint|TotalOLC|TotalPoint|
+----------+-----------+----------+--------+----------+
|         1|      08:00|        24|    NULL|      NULL|
|         1|      08:00|        24|       2|         0|
|         2|      04:00|        12|    NULL|      NULL|
|         2|      04:00|        12|    NULL|      NULL|
|         3|      04:00|        12|    NULL|      NULL|
|         3|      04:00|        12|    NULL|      NULL|
+----------+-----------+----------+--------+----------+
似乎当我尝试对单个表中的多个列求和时,它会在最终结果中创建多个行。现在,我想到的是使用CTE,将多个列分隔为多个CTE,并从所有CTE查询。或者甚至尝试创建临时表/表变量,查询每列的总和并存储/更新它

那么,你知道如何在不使用多个CTE或temp表的情况下实现我的结果吗


谢谢

您想将属于同一
员工ID的行组合在一起,因此这意味着聚合而不是窗口函数:

SELECT
    OT.EmployeeId,
    CONVERT(TIME, DATEADD(MS, SUM(DATEDIFF(MS, '00:00:00.000', OT.HourMargin)), '00:00:00.000')) AS TotalMargin,
    SUM(OT.OvertimePoint) AS TotalPoint,
    COALESCE(SUM(OLC.OLC), 0) AS TotalOLC,
    COALESCE(SUM(OLC.Trip), 0) AS TotalTrip
FROM @Overtime OT
LEFT JOIN @OLC OLC ON OLC.EmployeeId = OT.EmployeeId
GROUP BY OT.EmployeeId
我也不认为日期上的连接条件有什么意义,所以我删除了它。最后,您可以使用
coalesce()
为没有
OLC
的行返回
0

EmployeeId | TotalMargin | TotalPoint | TotalOLC | TotalTrip ---------: | :---------- | ---------: | -------: | --------: 1 | 08:00:00 | 24 | 4 | 0 2 | 04:00:00 | 12 | 0 | 0 3 | 04:00:00 | 12 | 6 | 12 员工ID | TotalMargin | TotalPoint | TotalOLC | TotalTrip ---------: | :---------- | ---------: | -------: | --------: 1 | 08:00:00 | 24 | 4 | 0 2 | 04:00:00 | 12 | 0 | 0 3 | 04:00:00 | 12 | 6 | 12
您已决定使用SUM OVER,但您遇到了多行的“问题”。。。这就是一个总和的作用;您可以设想,执行OVER(PARTITION…)会生成一个组,该组会自动连接回驱动表,因此最终会得到驱动表中的所有行以及重复的求和结果

以下是一个简单的数据集:

ProductID, Price
1, 100
1, 200
2, 300
2, 400
以下是一些查询和结果:

--perform a basic group and sum
SELECT ProductID, SUM(Price) S FROM x GROUP BY ProductID
1, 300
2, 700


--perform basic group/sum and join it back to the main table 
SELECT ProductID, Price, S
FROM
  x 
  INNER JOIN 
  (SELECT ProductID, SUM(Price) s FROM x GROUP BY ProductID) y 
  ON x.ProductID = y.ProductID
1, 100, 300
1, 200, 300
2, 300, 700
2, 400, 700


--perform a sum over, the partition here being the same as the earlier group
SELECT ProductID, Price, SUM(Price) OVER(PARTITION BY ProductID) FROM x
1, 100, 300
1, 200, 300
2, 300, 700
2, 400, 700
您可以看到后两种方法产生相同的结果,即附加额外的行和总行。如果您认为db内部就是这样做的,那么它可能会帮助您理解简单的窗口函数——它接受“partitionby”,使用它执行子查询group by,并将结果连接回分区中的任何列

看起来您真正想要的是一个简单的组:

SELECT
  OT.EmployeeId,
  CONVERT(TIME, DATEADD(MS, (SUM(DATEDIFF(MS, '00:00:00.000', OT.HourMargin))), '00:00:00.000')) AS TotalMargin,
  SUM(OT.OvertimePoint) AS TotalPoint,
  SUM(OLC.OLC) AS TotalOLC,
  SUM(OLC.Trip) AS TotalTrip
FROM @Overtime OT
LEFT JOIN @OLC OLC ON OLC.EmployeeId = OT.EmployeeId
                      AND OLC.OLCDate = OT.OvertimeDate
GROUP BY OT.EmployeeID

这确实完成了工作,看起来我需要更好地理解聚合和窗口。谢谢你的帮助。很高兴看到这么好的问题。