按日期排序的SQL组

时间:2015-05-13 09:22:54

标签: sql-server sql-server-2008 group-by

我已经按顺序阅读了一些关于分组的主题,这几乎是我需要的,但我找不到解决问题的方法。

我有一张这样的表:

PlanificatorPozitieID JalonID     DataStart               DataFinal               
--------------------- ----------- ----------------------- ----------------------- 
26                    46          2012-05-21 00:00:00.000 2012-05-31 00:00:00.000 
28                    48          2012-06-01 00:00:00.000 2012-06-01 00:00:00.000 
27                    60          2012-06-02 00:00:00.000 2012-06-02 00:00:00.000 
29                    60          2012-06-07 00:00:00.000 2012-06-08 00:00:00.000 
37                    60          2012-06-08 00:00:00.000 2012-06-10 00:00:00.000 
30                    65          2012-06-10 00:00:00.000 2012-06-13 00:00:00.000 
31                    65          2012-06-18 00:00:00.000 2012-06-24 00:00:00.000 
32                    65          2012-06-23 00:00:00.000 2012-07-01 00:00:00.000 
33                    66          2012-07-02 00:00:00.000 2012-07-02 00:00:00.000 
34                    66          2012-07-02 00:00:00.000 2012-07-05 00:00:00.000 
36                    66          2012-07-06 00:00:00.000 2012-07-10 00:00:00.000 


Desired output:

PlanificatorPozitieID JalonID     DataStart               DataFinal               
--------------------- ----------- ----------------------- ----------------------- 
26                    46          2012-05-21 00:00:00.000 2012-05-31 00:00:00.000 
28                    48          2012-06-01 00:00:00.000 2012-06-01 00:00:00.000 
27                    60          2012-06-02 00:00:00.000 2012-06-02 00:00:00.000 
29                    60          2012-06-07 00:00:00.000 2012-06-10 00:00:00.000 
30                    65          2012-06-10 00:00:00.000 2012-06-13 00:00:00.000 
31                    65          2012-06-18 00:00:00.000 2012-07-01 00:00:00.000 
33                    66          2012-07-02 00:00:00.000 2012-07-05 00:00:00.000 
36                    66          2012-07-06 00:00:00.000 2012-07-10 00:00:00.000 

所以我必须按JalonID进行分组,但只有在DataFinal> = DataStart的情况下才能进行分组。我想得到每个JalonID的时间段,但我想只得到没有暂停时间的句点。

家我清楚了。

select MIN(pp.DataStart) as DataStart, MAX(pp.DataFinal) as DataFinal, pp.JalonID FROM #PlanPozitii pp
GROUP BY pp.JalonID 

但是这个查询并不能满足我的条件,可以按连续的句点分组。

至于澄清。采取以下示例

30                    65          2012-06-10 00:00:00.000 2012-06-13 00:00:00.000 
31                    65          2012-06-18 00:00:00.000 2012-06-24 00:00:00.000 
32                    65          2012-06-23 00:00:00.000 2012-07-01 00:00:00.000

2012-06-13 00:00:00.000< 2012-06-18 00:00:00.000因此,PlanificatorPozitieID 3031之间不会发生任何群组。 但是2012-06-24 00:00:00.000> 2012-06-23 00:00:00.000所以现在PlanificatorPozitieID 3132之间会有一个小组。

所以从这3行我们将获得两行。

30                    65          2012-06-10 00:00:00.000 2012-06-13 00:00:00.000 
31                    65          2012-06-18 00:00:00.000 2012-07-01 00:00:00.000 





DECLARE @YourTable TABLE(PlanificatorPozitieID INT, JalonID INT,DataStart DATETIME, DataFinal DATETIME)
INSERT INTO @YourTable VALUES
(39,1223,'2015-02-16 00:00:00.000','2015-02-20 00:00:00.000'),
(43,1223,'2015-02-19 00:00:00.000','2015-02-24 00:00:00.000'),
(40,1223,'2015-02-23 00:00:00.000','2015-02-27 00:00:00.000'),
(42,1223,'2015-03-09 00:00:00.000','2015-03-13 00:00:00.000')
;WITH cte AS
(
SELECT  a.PlanificatorPozitieID, 
        a.JalonID, 
        a.DataStart, 
        COALESCE(b.DataFinal,a.datafinal) AS [DataFinal],
        ROW_NUMBER() OVER (PARTITION BY  a.JalonID ORDER BY DATEDIFF(dd,a.datastart, COALESCE(b.DataFinal,a.datafinal))) [rn],
        COUNT(*) OVER (PARTITION BY  a.JalonID) [cnt]
FROM    @YourTable a
        LEFT JOIN  @YourTable b 
        ON  a.JalonID = b.JalonID AND 
            b.DataStart BETWEEN a.DataStart AND a.DataFinal AND  
            a.PlanificatorPozitieID <> b.PlanificatorPozitieID AND 
            DATEDIFF(dd,a.DataStart,a.DataFinal) < DATEDIFF(dd,a.DataStart,b.DataFinal)
)
SELECT * 
FROM   cte 
WHERE  rn= 1 OR rn=cnt

结果:

PlanificatorPozitieID JalonID     DataStart               DataFinal               rn                   cnt
--------------------- ----------- ----------------------- ----------------------- -------------------- -----------
40                    1223        2015-02-23 00:00:00.000 2015-02-27 00:00:00.000 1                    4
43                    1223        2015-02-19 00:00:00.000 2015-02-27 00:00:00.000 4                    4

预期结果:

PlanificatorPozitieID JalonID     DataStart               DataFinal               
--------------------- ----------- ----------------------- ----------------------- 
39                    1223        2015-02-16 00:00:00.000 2015-02-27 00:00:00.000 
42                    1223        2015-03-09 00:00:00.000 2015-03-13 00:00:00.000 

3 个答案:

答案 0 :(得分:2)

我不知道它是否可以正常使用实际数据,因为我没有严格测试,但这是一个解决方案:

DECLARE @YourTable TABLE(PlanificatorPozitieID INT, JalonID INT,DataStart DATETIME, DataFinal DATETIME)
INSERT INTO @YourTable VALUES
(26,46,'2012-05-21 00:00:00.000','2012-05-31 00:00:00.000'), 
(28,48,'2012-06-01 00:00:00.000','2012-06-01 00:00:00.000'), 
(27,60,'2012-06-02 00:00:00.000','2012-06-02 00:00:00.000'), 
(29,60,'2012-06-07 00:00:00.000','2012-06-08 00:00:00.000'), 
(37,60,'2012-06-08 00:00:00.000','2012-06-10 00:00:00.000'), 
(30,65,'2012-06-10 00:00:00.000','2012-06-13 00:00:00.000'), 
(31,65,'2012-06-18 00:00:00.000','2012-06-24 00:00:00.000'), 
(32,65,'2012-06-23 00:00:00.000','2012-07-01 00:00:00.000'), 
(33,66,'2012-07-02 00:00:00.000','2012-07-02 00:00:00.000'), 
(34,66,'2012-07-02 00:00:00.000','2012-07-05 00:00:00.000'), 
(36,66,'2012-07-06 00:00:00.000','2012-07-10 00:00:00.000')

;WITH cte AS
(
SELECT  a.PlanificatorPozitieID, 
        a.JalonID, 
        a.DataStart, 
        COALESCE(b.DataFinal,a.datafinal) AS [DataFinal],
        ROW_NUMBER() OVER (PARTITION BY  a.JalonID ORDER BY DATEDIFF(dd,a.datastart, COALESCE(b.DataFinal,a.datafinal))) [rn],
        COUNT(*) OVER (PARTITION BY  a.JalonID) [cnt]
FROM    @YourTable a
        LEFT JOIN  @YourTable b 
        ON  a.JalonID = b.JalonID AND 
            b.DataStart BETWEEN a.DataStart AND a.DataFinal AND  
            a.PlanificatorPozitieID <> b.PlanificatorPozitieID AND 
            DATEDIFF(dd,a.DataStart,a.DataFinal) < DATEDIFF(dd,a.DataStart,b.DataFinal)
)
SELECT * 
FROM   cte 
WHERE  rn= 1 OR rn=cnt

答案 1 :(得分:0)

我找到了一个解决方案,因为它使用了2个游标,效率不高。但它适用于任何人需要一个例子的情况

DROP TABLE #DateTEst
DROP TABLE #pozitii
drop table #PozitiiJaloaneStandard
CREATE TABLE #DateTest (JalonStandardID int,DataStart datetime,DataFinal datetime)


INSERT INTO #DateTest VALUES (1,'2015-05-05','2015-05-08')
INSERT INTO #DateTest VALUES (1,'2015-05-09','2015-05-13')
INSERT INTO #DateTest VALUES (1,'2015-05-12','2015-05-15')
INSERT INTO #DateTest VALUES (1,'2015-05-16','2015-05-18')
INSERT INTO #DateTest VALUES (1,'2015-05-14','2015-05-19')
INSERT INTO #DateTest VALUES (2,'2015-05-05','2015-05-06')
INSERT INTO #DateTest VALUES (2,'2015-05-06','2015-05-07')
INSERT INTO #DateTest VALUES (2,'2015-05-06','2015-05-09')
INSERT INTO #DateTest VALUES (3,'2015-05-05','2015-05-07')
INSERT INTO #DateTest VALUES (3,'2015-05-08','2015-05-10')
INSERT INTO #DateTest VALUES (4,'2015-05-05','2015-05-08')
INSERT INTO #DateTest VALUES (5,'2015-05-07','2015-05-07')
INSERT INTO #DateTest VALUES (5,'2015-05-08','2015-05-08')
INSERT INTO #DateTest VALUES (5,'2015-05-09','2015-05-12')
INSERT INTO #DateTest VALUES (5,'2015-05-11','2015-05-12')
INSERT INTO #DateTest VALUES (6,'2015-05-05','2015-05-20')
INSERT INTO #DateTest VALUES (6,'2015-05-15','2015-05-18')




CREATE TABLE #Pozitii (DataStart datetime, DataFinal datetime)

CREATE TABLE #PozitiiJaloaneStandard ( JalonStandardID int, DataStart datetime, DataFinal datetime)



Declare @JalonStandarID int
DEclare @PlanificatorPozitieID int
Declare @DataStartPozitie datetime
Declare @DataFinalPozitie datetime 


DEclare @DataStartMin datetime
Declare @PozitieMinima int
Declare @DataFinalMin datetime


Declare @DataStartJalonStandard datetime
Declare @DataFinalJalonStandard datetime


Declare Crs_JaloaneStandard Cursor For
Select JalonStandardID
From #DateTest
ORDER BY JalonStandardID
Open Crs_JaloaneStandard
Fetch Next From Crs_JaloaneStandard Into 
@JalonStandarID
While @@Fetch_Status = 0 
    Begin
            INSERT INTO #Pozitii
            SELECT pp.DataStart,pp.DataFinal            
            FROM #DateTest pp
            WHERE pp.JalonStandardID = @JalonStandarID
            GROUP BY  pp.DataStart,pp.DataFinal



            SELECT @DataStartMin = MIN(DataStart) FROM #Pozitii

            SELECT   @DataFinalMin = DataFinal FROM 
             #Pozitii WHERE DataStart = @DataStartMin



            Declare Crs_Pozitii Cursor For
            SELECT 
            p.DataStart,p.DataFinal
            FROM #Pozitii p
            ORDER by p.DataStart ASC
            Open Crs_Pozitii
            Fetch Next From Crs_Pozitii Into
            @DataStartPozitie,@DataFinalPozitie
            while @@FETCH_STATUS = 0 
            begin

                    if (@DataFinalMin > @DataStartPozitie) and (@DataFinalMin <= @DataFinalPozitie )
                    begin 
                        set @DataFinalMin = @DataFinalPozitie
                    end
                    if (@DataFinalMin <= @DataStartPozitie) begin
                         INSERT INTO #PozitiiJaloaneStandard VALUES (@JalonStandarID,@DataStartMin,@DataFinalMin)
                         set @DataFinalMin = @DataFinalPozitie
                         set @DataStartMin = @DataStartPozitie      
                         print @DataStartPozitie
                         print @DataFinalPozitie                    
                    end



            Fetch Next From Crs_Pozitii Into 
            @DataStartPozitie,@DataFinalPozitie
            End 

            INSERT INTO #PozitiiJaloaneStandard VALUES (@JalonStandarID,@DataStartMin,@DataFinalMin)

            DELETE FROM #Pozitii
            Close Crs_Pozitii
            Deallocate Crs_Pozitii

    Fetch Next From Crs_JaloaneStandard Into 
    @JalonStandarID
    End

Close Crs_JaloaneStandard
Deallocate Crs_JaloaneStandard




SELECT * FROM #PozitiiJaloaneStandard
GROUP BY JalonStandardID,DataStart,DataFinal

答案 2 :(得分:-1)

https://msdn.microsoft.com/en-us/library/hh231256.aspx

我正在寻找LAG()函数,它可以访问查询中的前一行。我的想法是计算当前行和上一行之间的差异,以使列分组;

with a as (
select 1 as ID, 1 as A, 2 as B union all
select 1 as ID, 2 as A, 3 as B union all
select 1 as ID, 3 as A, 4 as B union all
select 1 as ID, 4 as A, 5 as B union all
select 1 as ID, 6 as A, 7 as B
) 
select ID, A, B, A-LAG(B,1,0) OVER (order by ID) as koe from a where B > A

如果您运行该查询,则会得到结果为;

ID          A           B           koe
----------- ----------- ----------- -----------
1           1           2           1
1           2           3           0
1           3           4           0
1           4           5           0
1           6           7           1

想象一下A是DataStart而B是DataFinal,并且计算出的koe是差异的,因为你可以看到它可以在除第一行之外的所有行上运行...第一行在不存在的行之间获得差异(因此它的0)。但这是我开始尝试的方向。