SQL合并startdate和enddate

时间:2014-10-08 12:28:13

标签: tsql date merge

我想从日志事件中合并几个开始日期和结束日期(因此一个日期为1行)。

输入表是:

Ord    Desc2    Date_Time
--------------------------
0      Down     1/1/2014      ==> Not merged because no Up after
1      Down     1/2/2014      ==> Rows 1 and 2 should be merged
2      Up       1/3/2014      
5      Down     1/4/2014      ==> Rows 5 and 12 should be merged
12     Up       1/6/2014      
13     Up       1/7/2014      ==> Not merged because no Down before

所以我正在寻找的结果将是:

Ord    DesactivationDateTime    ActivationDateTime
----------------------------------------------------
0      1/1/2014   
1      1/2/2014                 1/3/2014
5      1/4/2014                 1/6/2014
13                              1/7/2014

SQL请求我发现这是一个但它只适用于UP / Down夫妇:

SELECT EventsDesactivation.Ord
    , EventsDesactivation.Desc2
    , EventsDesactivation.Date_Time AS DesactivationDateTime
    , MIN(EventsActivation.Date_Time) AS ActivationDateTime
FROM Journal AS EventsDesactivation

LEFT OUTER JOIN Journal AS EventsActivation

ON EventsActivation.Module=EventsDesactivation.Module --This is one of common rows not displayed in this sample...

WHERE
    (EventsDesactivation.Desc2 = 'Down') 
    AND (EventsActivation.Desc2  = 'Up')
    AND (EventsActivation.Ord > EventsDesactivation.Ord)
GROUP BY EventsDesactivation.Ord, EventsDesactivation.Desc2, EventsDesactivation.Date_Time

如果您帮助我找到解决方案,我将不胜感激! 我的最后一个想法是在夫妻和单打行上做一个疯狂的UNION ALL和最后的GROUP BY ......

感谢您的帮助!

此致 弗朗索瓦

2 个答案:

答案 0 :(得分:0)

这符合您的样本数据和预期结果,但我有一种唠叨的感觉,我错过了一些边缘案例:

declare @t table (Ord int, Desc2 varchar(13),Date_Time date)
insert into @t(Ord,Desc2,Date_Time) values
(0     ,'Down','20140101'),
(1     ,'Down','20140102'),
(2     ,'Up','20140103'),    
(5     ,'Down','20140104'),
(12    ,'Up','20140106'),
(13    ,'Up','20140107')

;With numbered as (
    select Ord,Desc2,Date_Time,
        ROW_NUMBER() OVER (ORDER BY Ord /* or date_time? */) as rn
    from
        @t
)
select
    CASE WHEN n1.Desc2='Up' and n2.Desc2='Up' THEN n2.Ord ELSE n1.Ord END,
    CASE WHEN n1.Desc2='Up' and n2.Desc2='Up' THEN NULL ELSE n1.Date_Time END,
    CASE WHEN n1.Desc2='Down' and n2.Desc2='Down' THEN NULL ELSE n2.Date_Time END
from
    numbered n1
full outer join
    numbered n2
        on
            n1.rn = n2.rn - 1
where
    not (n1.Desc2='Up' and n2.Desc2='Down')

基本上,我们将每行与逻辑上的行连接起来。我们忽略后跟Up行的Down行。然后我们只需要计算Down,Up(正常),Down,Down(仅报告第一行的值)或Up,Up(仅报告第二行的值)

结果:

----------- ---------- ----------
0           2014-01-01 NULL
1           2014-01-02 2014-01-03
5           2014-01-04 2014-01-06
13          NULL       2014-01-07

答案 1 :(得分:0)

我已将您的想法应用到我的现实世界中,并且它在存储过程中完美运行。感谢那! 但是我的SQL客户端不支持存储过程...对我感到羞耻!

所以我决定创建一个表函数(带有pamareters)来调用这个SQL代码。

不幸的是,我没有找到使用中间编号表的方法(在我使用中称为Event)... 我在线上发现了以下错误“; WITH Events AS”: ==>函数中包含的select语句不能将数据返回给客户端。

这是我完成的功能代码:

CREATE FUNCTION fnSensorsDesactivations 
(
    @dateStartInString nvarchar(50) = '',
    @dateEndInString nvarchar(50) = '',
    @Unit nvarchar(50) = null,
    @HoursToAddFromGMT int = -2,
    @DesactivationEventsFilter nvarchar(50) = 'Validation et Désactivation%',
    @BeforeDesactivationComment nvarchar(50) = 'Validation et Désactivation Capteur par ',
    @AfterDesactivationComment nvarchar(50) = '. Commentaire : ',
    @ActivationEventsFilter nvarchar(50) = 'Activation Capteur par%',
    @BeforeActivationUsername nvarchar(50) = 'Activation Capteur par '
)
RETURNS @TableTempToReturn TABLE 
(
    -- Add the column definitions for the TABLE variable here
    --Ord int,
    Unit nvarchar(50),
    Module nvarchar(255),
    Module_Description nvarchar(255),
    DésactivationQui nvarchar(255),
    DésactivationDateTime nvarchar(255),
    DésactivationMessage nvarchar(255),
    ActivationQui nvarchar(255),
    ActivationDateTime nvarchar(255)
)
AS
BEGIN
    DECLARE @ExcludeOrds AS nvarchar(255) -- Must be comma separated and also at first and last character
    DECLARE @dateStart AS datetime -- to cast datetime from string because Dream Report is not able to pass parameters with formulas
    DECLARE @dateEnd AS datetime -- to cast datetime from string because Dream Report is not able to pass parameters with formulas
    SET @ExcludeOrds=',,,,,,,,,'
IF @dateStartInString='' OR @dateEndInString=''
    BEGIN
        --Init dates from yesterday to today if they are null
        SET @dateEnd=GETDATE()
        SET @dateStart=DATEADD(year, -1, @DateEnd)
    END
ELSE
    BEGIN
        --Convert datetime from string to datetime format + hours from GMT to follow local datetime settings
        SET @dateEnd=DATEADD(hour, @HoursToAddFromGMT, CONVERT(datetime, @dateEndInString,  121))
        SET @dateStart=DATEADD(hour, @HoursToAddFromGMT, CONVERT(datetime, @dateStartInString,  121))
    END
IF @Unit IS NULL SET @Unit='WIP-BC2'

--Calculate positions/orders of differents Activation and desactivation events
;WITH Events AS   -- Here is my SQL error: select statements included whithin a function cannot return a data to a client.

(
    SELECT Ord, Unit, Module, Module_Description, Desc2, Date_Time,
        ROW_NUMBER() OVER (ORDER BY Unit, Module, Ord) AS rn
    FROM
        EJournal.dbo.Journal
    WHERE
        Date_Time <= @dateEnd
        AND Unit = @Unit
        AND (Desc2 like @DesactivationEventsFilter
                OR Desc2 like @ActivationEventsFilter)
        --AND (Date_Time like @ActivationEventsFilter and Date_Time<=@dateStart)
        AND CHARINDEX(CAST(Ord AS nvarchar), @ExcludeOrds,1)=0
)

--Depending on desactivation and activation orders, select good Events in Activation/descativation columns
SELECT
    --n1.Ord,n2.Ord, n1.Desc2, n2.Desc2,
    n1.Module
    , n1.Module_Description
    , CASE
        WHEN n1.Desc2 like @ActivationEventsFilter AND n2.Desc2 like @ActivationEventsFilter
            THEN ''
        WHEN n1.Desc2 like @DesactivationEventsFilter AND (n2.Desc2 like @ActivationEventsFilter OR n2.Ord IS NULL)
            THEN ISNULL(LEFT(SUBSTRING(n1.Desc2, LEN(@BeforeDesactivationComment)+2, 255 )
                    , CHARINDEX(@AfterDesactivationComment, SUBSTRING(n1.Desc2, LEN(@BeforeDesactivationComment)+2, 255)) - 1), '')
        WHEN n1.Desc2 like @DesactivationEventsFilter AND (n2.Desc2 like @DesactivationEventsFilter OR n2.Ord IS NULL)
            THEN ISNULL(LEFT(SUBSTRING(n1.Desc2, LEN(@BeforeDesactivationComment)+2, 255 ), '')
                    , CHARINDEX(@AfterDesactivationComment, SUBSTRING(n1.Desc2, LEN(@BeforeDesactivationComment)+2, 255)) - 1)
        ELSE ''
        END AS DésactivationQui
    , CASE
        WHEN n1.Desc2 like @ActivationEventsFilter AND n2.Desc2 like @ActivationEventsFilter
            THEN ''
        WHEN n1.Desc2 like @DesactivationEventsFilter AND (n2.Desc2 like @ActivationEventsFilter OR n2.Ord IS NULL)
            THEN ISNULL(CONVERT(nvarchar, n1.Date_Time,  121), '')
        WHEN n1.Desc2 like @DesactivationEventsFilter AND (n2.Desc2 like @DesactivationEventsFilter OR n2.Ord IS NULL)
            THEN ISNULL(CONVERT(nvarchar, n1.Date_Time,  121), '')
        ELSE ''
    END AS DésactivationDateTime
    , CASE
        WHEN n1.Desc2 like @ActivationEventsFilter AND n2.Desc2 like @ActivationEventsFilter
            THEN ''
        WHEN n1.Desc2 like @DesactivationEventsFilter AND (n2.Desc2 like @ActivationEventsFilter OR n2.Ord IS NULL)
            THEN ISNULL(SUBSTRING(n1.Desc2, CHARINDEX(@AfterDesactivationComment, n1.Desc2)+LEN(@AfterDesactivationComment), 255 ) , '')
        WHEN n1.Desc2 like @DesactivationEventsFilter AND (n2.Desc2 like @DesactivationEventsFilter OR n2.Ord IS NULL)
            THEN ISNULL(SUBSTRING(n1.Desc2, CHARINDEX(@AfterDesactivationComment, n1.Desc2)+LEN(@AfterDesactivationComment), 255 ) , '')
        ELSE ''
    END AS DésactivationMessage
    , CASE
        WHEN n1.Desc2 like @ActivationEventsFilter AND n2.Desc2 like @ActivationEventsFilter
            THEN ISNULL(SUBSTRING(n2.Desc2, LEN(@BeforeActivationUsername)+2, 255 ),'')
        WHEN (n1.Desc2 like @DesactivationEventsFilter OR n1.Ord IS NULL) AND n2.Desc2 like @ActivationEventsFilter
            THEN ISNULL(SUBSTRING(n2.Desc2, LEN(@BeforeActivationUsername)+2, 255 ), '')
        --WHEN n1.Desc2 like @DesactivationEventsFilter AND n2.Desc2 like @DesactivationEventsFilter THEN ''
        --  THEN ''
        ELSE ''
    END AS ActivationQui
    , CASE
        WHEN n1.Desc2 like @ActivationEventsFilter AND n2.Desc2 like @ActivationEventsFilter
            THEN ISNULL(CONVERT(nvarchar, n2.Date_Time,  121),'')
        WHEN (n1.Desc2 like @DesactivationEventsFilter OR n1.Ord IS NULL) AND n2.Desc2 like @ActivationEventsFilter
            THEN ISNULL(CONVERT(nvarchar, n2.Date_Time,  121),'')
        --WHEN n1.Desc2 like @DesactivationEventsFilter AND n2.Desc2 like @DesactivationEventsFilter
        --  THEN ''
        ELSE ''
    END AS ActivationDateTime

FROM
    Events n1
FULL OUTER JOIN
    Events n2
    ON      n1.rn = n2.rn - 1
            AND n1.Unit=n2.Unit
            AND n1.Module=n2.Module

WHERE NOT (n1.Desc2 like @ActivationEventsFilter AND n2.Desc2 like @DesactivationEventsFilter)
        AND n1.Desc2 like @DesactivationEventsFilter
        AND n1.Date_Time <= @dateEnd
        --AND n2.Date_Time <= @dateEnd
        AND (n2.Ord IS NULL OR n2.Date_Time>=@dateStart)

RETURN 

END

你能为它提供一个神奇的解决方案吗?

再次感谢您的帮助! 弗朗索瓦