我想从日志事件中合并几个开始日期和结束日期(因此一个日期为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 ......
感谢您的帮助!
此致 弗朗索瓦
答案 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
你能为它提供一个神奇的解决方案吗?
再次感谢您的帮助! 弗朗索瓦