我有一个数据表(将有数百万条记录,但我会在这里简化),看起来像这样。
ID APPROVAL_DT DAY_DT TRANS_COUNT SALE_AMOUNT
1 2010-04-22 2010-04-27 2 260
1 2010-04-22 2010-04-28 1 40
2 2010-03-28 2010-04-02 1 5
2 2010-03-28 2010-04-03 5 10
2 2010-03-28 2010-04-04 1 20
3 2010-04-25 2010-05-01 6 10
3 2010-04-25 2010-05-02 4 10
4 2010-06-01 2010-06-07 1 5
我需要找出每个ID的DAY_DT,其中所有之前和当前DAY_DT TRANS_COUNTs的总和> = 10或所有之前和当前DAY_DT的总和SALE_AMOUNTs> = 25
因此,应用于上表的查询结果将是
ID APPROVAL_DT ACTIVATED_DT
1 2010-04-22 2010-04-27
2 2010-03-28 2010-04-04
3 2010-04-25 2010-05-02
4 2010-06-01 NULL
有什么想法吗?
答案 0 :(得分:1)
您拥有每个ID有多少条记录?
Itzik Ben Gan对SQL Server 2008中解决运行总计的各种方法进行了比较。
他在测试中得出的结论是,每个分区最多有15个记录triangular Join最好。那时SQL CLR方法变得更好了。三角形连接继续优于沼泽标准TSQL光标,直到分区大小达到500。
显然你的里程可能会有所不同,但我认为这些数字很有用。
答案 1 :(得分:1)
我认为你的意思是你要在ID中找到 first day_dt,其中前一天的总和是trans_count> = 10或者sales_amount> = 25。你这叫发现一天'activated_dt'。您的描述与此完全不同,因为它没有指定您只想要第一个日,并且它要求所有之前天的总和,而您的示例结果显示总和最多当天。
我同意马丁的观点,一个总计将是表现最好的,因为它可以在一次扫描表中产生结果。
没有运行总计的结果必须计算每天day_dt的前几天总数,然后为每个ID选择第一个:
with cte1 as (
select
t.id,
t.approval_dt,
t.day_dt as activated_dt
from Table t
cross apply (
select sum(trans_count) as sum_tc,
sum(sale_amount) as sum_sa,
max(day_dt) as max_day_dt
from table c
where c.id = t.id
and c.day_dt <= t.day_dt) as p
where p.sum_tc >= 10
or p.sum_sa >=25)
, cte2 as (
select id
, approval_dt
, activated_dt
, row_number() over (partition by id order by activated_dt) as rn
from cte1)
select *
from cte2
where rn = 1;
答案 2 :(得分:1)
好的。振作起来。我通过使用运行的总UPDATE方法使用了一点作弊方法。有一些怪癖,所以厌倦了把它放在生产代码中。其中最大的是如何遍历表。应该在APPROVAL_DAY列上放置聚簇索引,以确保不拆分日期。无论如何,这里也是。
CREATE TABLE #test
(
ID int,
APPROVAL_DT date,
DAY_DT date,
TRANS_COUNT int,
SALE_AMOUNT int,
DailyTransCount int,
DailySalesTotal int
)
INSERT INTO #test
SELECT 1,'2010-04-22','2010-04-27',2,260,0,0 UNION ALL
SELECT 1,'2010-04-22','2010-04-28', 1,40, 0,0 UNION ALL
SELECT 2,'2010-03-28','2010-04-02', 1,5, 0,0 UNION ALL
SELECT 2,'2010-03-28','2010-04-03', 5,10, 0,0 UNION ALL
SELECT 2,'2010-03-28','2010-04-04', 1,20, 0,0 UNION ALL
SELECT 3,'2010-04-25','2010-05-01', 6,10, 0,0 UNION ALL
SELECT 3,'2010-04-25','2010-05-02', 4,10, 0,0 UNION ALL
SELECT 4,'2010-06-01','2010-06-07', 1,5, 0,0
DECLARE @PreviousDay date; SET @PreviousDay = '29991231'
DECLARE @DailyTransCount int; SET @DailyTransCount = 0
DECLARE @DailySalesTotal int; SET @DailySalesTotal = 0
DECLARE @Group int; SET @Group = 0
UPDATE #test
SET DailyTransCount = 0,
DailySalesTotal = 0
UPDATE #test
SET @DailyTransCount = DailyTransCount = CASE WHEN APPROVAL_DT = @PreviousDay THEN @DailyTransCount + Trans_Count ELSE Trans_Count END,
@DailySalesTotal = DailySalesTotal = CASE WHEN APPROVAL_DT = @PreviousDay THEN @DailySalesTotal + SALE_AMOUNT ELSE SALE_AMOUNT END,
@PreviousDay = APPROVAL_DT
SELECT Y.ID, X.APPROVAL_DT, X.DAY_DT FROM
(SELECT DISTINCT(ID) FROM #test T) Y
LEFT JOIN ( SELECT ID, APPROVAL_DT, MIN(DAY_DT) AS DAY_DT FROM #test
WHERE DailyTransCount >= 10 OR DailySalesTotal >= 25
GROUP BY ID, APPROVAL_DT ) X ON X.ID = Y.ID
我应该解释一些事情:我在表的末尾创建了两个列。您需要将其放入临时表(或永久表)以将总计推入。在我将所有总计推入列后,它只是一个选择来检索结果。有关此技术的更多信息here。请注意,此解决方案很快,但对它有点不安全。