2014-10-08 2 views
1

Я хочу объединить несколько дат начала и окончание из события журнала (так что 1 строка для одной даты).SQL merge startdate и endate

Входной стол:

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 запрос я обнаружил, это один, но он работает только для вверх/вниз пара :

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 ...

Спасибо за вашу помощь!

С уважением, Франсуа

ответ

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 
+0

Отлично! Спасибо за этот ответ! Было ли у вас решение иметь только один SELECT с ROW_NUMBER()? Я не уверен, что мой последний SQL-клиент позволит такие запросы ... Что бы ни звучало, звучит хорошо! :) – Francois

0

Я применил вашу идею к моему реальному миру и отлично работает в хранимой процедуре. Спасибо за это! НО мой SQL-клиент не поддерживает хранимую процедуру ... Позор мне!

Поэтому я решил создать функцию таблицы (с помощью pamareters), чтобы вызвать этот код SQL.

К сожалению, я не нашел способ использовать вашу промежуточную пронумерованную таблицу (называемую «Событие в моем использовании») ... У меня была следующая ошибка в строке «; WITH Events AS»: ==> функция не может вернуть данные клиенту.

Вот код функции я сделал:

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<[email protected]) 
     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>[email protected]) 

RETURN 

END

ли у Вас есть волшебное решение для этого?

Еще раз спасибо за помощь! François