SQL 服务器条件小计查询
SQL Server conditional subtotal query
给出以下 table:
create table #T
(
user_id int,
project_id int,
datum datetime,
status varchar(10),
KM int
)
insert into #T values
(1, 1, '20160301 10:25', 'START', 1000),
(1, 1, '20160301 10:28', 'PASS', 1008),
(2, 2, '20160301 10:29', 'START', 2000),
(1, 1, '20160301 11:08', 'STOP', 1045),
(3, 3, '20160301 10:25', 'START', 3000),
(2, 2, '20160301 10:56', 'STOP', 2020),
(1, 4, '20160301 15:00', 'START', 1045),
(4, 5, '20160301 15:10', 'START', 400),
(1, 4, '20160301 15:10', 'PASS', 1060),
(1, 4, '20160301 15:20', 'PASS', 1080),
(1, 4, '20160301 15:30', 'STOP', 1080),
(4, 5, '20160301 15:40', 'STOP', 450),
(3, 3, '20160301 16:25', 'STOP', 3200)
我必须对给定用户和项目的开始和停止状态之间的轨道长度求和
预期结果是这样的:
user_id project_id datum TOTAL_KM
----------- ----------- ---------- -----------
1 1 2016-03-01 45
1 4 2016-03-01 35
2 2 2016-03-01 20
3 3 2016-03-01 200
4 5 2016-03-01 50
如何在不使用集群的情况下实现这一点?
性能是个问题(我每个月有超过 100 万条记录,我们必须将数据保存数年)
说明:
我们可以忽略状态为 "PASS" 的记录。基本上,我们必须从给定用户和项目的 STOP 记录中减去 START 记录的 KM 值。
START 和 STOP 之间可以有数百条记录(如示例数据中所述)
日期应该是开始的日期(如果我们有超过午夜的交货)
我想我应该有一个带有 OVER() 子句的 SELECT,但我不知道如何制定我的查询以遵守这些条件。
有什么想法吗?
这可以通过简单的自连接来实现。
其中一个例子:(这可能不是确切的查询,只是一个想法)
Select
a.user_id,
a.project_id,
b.datum as StartDate,
a.KM-b.KM as TotalKM
From #T a
Where status = 'STOP'
Join
(
Select user_id, project_id, KM From #t Where
status = 'START'
) b ON b.user_id = a.user_id, b.project_id = a.project_id
#T b
SELECT t.[user_id],
t.project_id,
cast(t.datum as date) as datum,
t1.KM- t.KM as KM
FROM #T t
INNER JOIN #T t1
ON t.[user_id]=t1.[user_id] and t.project_id = t1.project_id
WHERE t.[status] = 'START' and t1.[status] = 'STOP'
ORDER BY t.[user_id],
t.project_id,
cast(t.datum as date)
输出:
user_id project_id datum KM
----------- ----------- ---------- -----------
1 1 2016-03-01 45
1 4 2016-03-01 35
2 2 2016-03-01 20
3 3 2016-03-01 200
4 5 2016-03-01 50
(5 row(s) affected)
给出以下 table:
create table #T
(
user_id int,
project_id int,
datum datetime,
status varchar(10),
KM int
)
insert into #T values
(1, 1, '20160301 10:25', 'START', 1000),
(1, 1, '20160301 10:28', 'PASS', 1008),
(2, 2, '20160301 10:29', 'START', 2000),
(1, 1, '20160301 11:08', 'STOP', 1045),
(3, 3, '20160301 10:25', 'START', 3000),
(2, 2, '20160301 10:56', 'STOP', 2020),
(1, 4, '20160301 15:00', 'START', 1045),
(4, 5, '20160301 15:10', 'START', 400),
(1, 4, '20160301 15:10', 'PASS', 1060),
(1, 4, '20160301 15:20', 'PASS', 1080),
(1, 4, '20160301 15:30', 'STOP', 1080),
(4, 5, '20160301 15:40', 'STOP', 450),
(3, 3, '20160301 16:25', 'STOP', 3200)
我必须对给定用户和项目的开始和停止状态之间的轨道长度求和 预期结果是这样的:
user_id project_id datum TOTAL_KM
----------- ----------- ---------- -----------
1 1 2016-03-01 45
1 4 2016-03-01 35
2 2 2016-03-01 20
3 3 2016-03-01 200
4 5 2016-03-01 50
如何在不使用集群的情况下实现这一点? 性能是个问题(我每个月有超过 100 万条记录,我们必须将数据保存数年)
说明: 我们可以忽略状态为 "PASS" 的记录。基本上,我们必须从给定用户和项目的 STOP 记录中减去 START 记录的 KM 值。 START 和 STOP 之间可以有数百条记录(如示例数据中所述) 日期应该是开始的日期(如果我们有超过午夜的交货)
我想我应该有一个带有 OVER() 子句的 SELECT,但我不知道如何制定我的查询以遵守这些条件。
有什么想法吗?
这可以通过简单的自连接来实现。
其中一个例子:(这可能不是确切的查询,只是一个想法)
Select
a.user_id,
a.project_id,
b.datum as StartDate,
a.KM-b.KM as TotalKM
From #T a
Where status = 'STOP'
Join
(
Select user_id, project_id, KM From #t Where
status = 'START'
) b ON b.user_id = a.user_id, b.project_id = a.project_id
#T b
SELECT t.[user_id],
t.project_id,
cast(t.datum as date) as datum,
t1.KM- t.KM as KM
FROM #T t
INNER JOIN #T t1
ON t.[user_id]=t1.[user_id] and t.project_id = t1.project_id
WHERE t.[status] = 'START' and t1.[status] = 'STOP'
ORDER BY t.[user_id],
t.project_id,
cast(t.datum as date)
输出:
user_id project_id datum KM
----------- ----------- ---------- -----------
1 1 2016-03-01 45
1 4 2016-03-01 35
2 2 2016-03-01 20
3 3 2016-03-01 200
4 5 2016-03-01 50
(5 row(s) affected)