拿两个......
实际数据:
division ID date flag
ABC123 ZZZ123 1/17/2013 Y
ABC123 ZZZ123 1/25/2013 N
ABC123 ZZZ123 2/22/2013 Y
ABC123 ZZZ123 2/26/2013 N
ABC123 YYY222 3/20/2013 Y
ABC123 YYY222 5/17/2013 N
XYZ456 ZZZ999 1/15/2012 N
XYZ456 ZZZ999 1/30/2012 N
XYZ456 ZZZ123 2/09/2012 N
XYZ456 ZZZ123 4/13/2012 Y
XYZ456 ZZZ123 6/23/2012 N
XYZ456 ZZZ123 10/5/2012 Y
XYZ456 ZZZ123 11/18/2012 N
我需要构建一个新列ORDER_group,它将根据以下规则进行填充:
预期结果:
division ID date flag ORDER_group
ABC123 ZZZ123 1/17/2013 Y 1
ABC123 ZZZ123 1/25/2013 N 1
ABC123 ZZZ123 2/22/2013 Y 2
ABC123 ZZZ123 2/26/2013 N 2
ABC123 YYY222 3/20/2013 Y 1
ABC123 YYY222 5/17/2013 N 1
XYZ456 ZZZ999 1/15/2012 N 1
XYZ456 ZZZ999 1/30/2012 N 1
XYZ456 ZZZ123 2/09/2012 N 1
XYZ456 ZZZ123 4/13/2012 Y 2
XYZ456 ZZZ123 6/23/2012 N 2
XYZ456 ZZZ123 10/5/2012 Y 3
XYZ456 ZZZ123 11/18/2012 N 3
理想情况下,这应该在没有循环/游标的情况下完成,除非有CTE /临时表的性能原因。填充此新列的最佳方法是什么?
非常感谢任何帮助。
实际数据的SQL Fiddler:http://sqlfiddle.com/#!3/5cca0/2
答案 0 :(得分:1)
所以这是一种方法。它基于How do I calculate a running total in SQL without using a cursor?确实存在一些缺陷。我在建议中使用了一个索引,它使得排序工作 DESPITE 事实上不能保证更新的顺序。
对于Aaron Bertrand的治疗,它也值得你Calculate running total / running balance。
这里可能聪明的位是将Y / N转换为1/0以用于计算。
CREATE TABLE Orders (division CHAR(6),ID CHAR(6),dat DATETIME, flag CHAR(1))
INSERT INTO Orders VALUES
('ABC123','ZZZ123','01/17/2013','Y')
,('ABC123','ZZZ123','01/25/2013','N')
,('ABC123','ZZZ123','01/25/2013','N')
,('ABC123','ZZZ123','01/25/2013','N')
,('ABC123','ZZZ123','01/25/2013','N')
,('ABC123','ZZZ123','02/22/2013','Y')
,('ABC123','ZZZ123','02/26/2013','N')
,('ABC123','YYY222','03/20/2013','Y')
,('ABC123','YYY222','05/17/2013','N')
,('XYZ456','ZZZ999','01/15/2012','N')
,('XYZ456','ZZZ999','01/30/2012','N')
,('XYZ456','ZZZ123','02/09/2012','N')
,('XYZ456','ZZZ123','04/13/2012','Y')
,('XYZ456','ZZZ123','06/23/2012','N')
,('XYZ456','ZZZ123','010/5/2012','Y')
,('XYZ456','ZZZ123','11/18/2012','N')
CREATE TABLE #Orders (division CHAR(6), ID CHAR(6), dat DATETIME, flag CHAR(1),flag_int INTEGER, rn BIGINT, OrderGroup INT)
CREATE CLUSTERED INDEX IDX_C_Temp_Order ON #Orders(division, id,rn)
INSERT INTO #Orders (division, id,dat,flag,flag_int,rn,OrderGroup)
SELECT division
,ID
,dat
,flag
,CASE flag WHEN 'y' THEN 1 ELSE 0 END flag_int
,ROW_NUMBER() OVER (PARTITION BY division, id ORDER BY dat) rn
,0 OrderGroup
FROM Orders
DECLARE @OrderGroup INT = 0
UPDATE #Orders
SET @OrderGroup = OrderGroup = CASE WHEN rn = 1 THEN 1 ELSE @OrderGroup + flag_int END
FROM #Orders
SELECT *
FROM #Orders
ORDER BY division
,ID
,rn
DROP TABLE #Orders
答案 1 :(得分:0)
一个更简单的解决方案怎么样?
WITH Data AS (
SELECT
*,
Num = Row_Number() OVER (PARTITION BY division, ID ORDER BY date)
FROM MyTable
)
SELECT
*
FROM
Data D
CROSS APPLY (
SELECT Count(*)
FROM Data D2
WHERE
D.division = D2.division
AND D.ID = D2.ID
AND D.date >= D2.date
AND (D2.flag = 'Y' OR D2.Num = 1)
) G (OrderGroup)
;
<强> See it live in a SQL Fiddle 强>