我有一个设计不佳的表,我没有设计,无法修复/更改,因为写入它的第三方黑莓应用程序。关键是有一个开始记录和一个停止记录,用于跟踪没有连接的事件或验证是否匹配。黑莓应用程序无需将这些记录绑定在一起。我试图在其自身上创建一个连接,并使用begin创建临时表,并将一个结尾创建为全外连接它们。问题是我有重复的条目,条目应标记为没有配偶。现有数据的行和开始和结束记录都没有配对。我搜索了SO的答案,我发现了一些让我这么远的答案。我知道它很长,很抱歉。
有一个 单 表,令人惊讶的是有一个主键。没有枢轴/交叉表。结构是
ID (int PK)
activityType varchar
beginEnd varchar ('begin' or 'end')
businessKey varchar nullable
date DATETIME
technician varchar
以下列也在表中,但可以为空,对查询不重要。
dateSubmitted DATETIME
gpsLatitude float
gpsLongitude float
note varchar
odometer int
我现在的查询仍然存在欺骗:显示和排序ID和EndID仅用于调试
DECLARE @DateFrom DATETIME
DECLARE @DateTo DATETIME
SET @DateFrom='20101101'
SET @DateTo='20101102'
DECLARE @Incomplete VARCHAR(15)
SET @Incomplete = 'Incomplete'
DECLARE @StartEvents TABLE
(
[id] [numeric](19, 0) NOT NULL,
[activityType] [varchar](255) NOT NULL,
[beginEnd] [varchar](255) NULL,
[businessKey] [varchar](255) NULL,
[date] [datetime] NOT NULL,
[dateSubmitted] [datetime] NULL,
[gpsLatitude] [float] NULL,
[gpsLongitude] [float] NULL,
[note] [varchar](255) NULL,
[odometer] [int] NULL,
[technician] [varchar](255) NOT NULL
)
INSERT @StartEvents
([ID],[activityType],[beginEnd],[businessKey],[date],[dateSubmitted],[gpsLatitude]
,[gpsLongitude],[note],[odometer],[technician])
SELECT *
FROM dbo.TimeEntry
WHERE
[date] between @DateFrom AND @DateTo
AND beginEnd = 'Begin'
--AND [technician] = 'FRED'
ORDER by technician
------------------------------------------------------------
DECLARE @EndEvents TABLE
(
[id] [numeric](19, 0) NOT NULL,
[activityType] [varchar](255) NOT NULL,
[beginEnd] [varchar](255) NULL,
[businessKey] [varchar](255) NULL,
[date] [datetime] NOT NULL,
[dateSubmitted] [datetime] NULL,
[gpsLatitude] [float] NULL,
[gpsLongitude] [float] NULL,
[note] [varchar](255) NULL,
[odometer] [int] NULL,
[technician] [varchar](255) NOT NULL
)
INSERT @EndEvents
([ID],[activityType],[beginEnd],[businessKey],[date],[dateSubmitted],[gpsLatitude]
,[gpsLongitude],[note],[odometer],[technician])
SELECT *
FROM dbo.TimeEntry
WHERE
[date] between @DateFrom AND @DateTo AND
beginEnd = 'End'
--AND [technician] = 'FRED'
ORDER by technician
-- And then a conventional SELECT
SELECT
StartEvents.id
,EndEvents.id AS EndID
,COALESCE(
StartEvents.activityType ,EndEvents.activityType ,'Not Available'
) AS ActivityType
--,StartEvents.beginEnd as [Begin]
--,EndEvents.beginEnd AS [End]
,COALESCE (
convert(VARCHAR(12), StartEvents.[date], 103),
convert(VARCHAR(12), EndEvents.[date], 103), @Incomplete
) as [Event Date]
,COALESCE (
convert(VARCHAR(12), EndEvents.[date], 103), @Incomplete
) as [End Date]
,COALESCE(
CONVERT(VARCHAR(5) , StartEvents.dateSubmitted , 108) , @Incomplete
) AS StartTime
,COALESCE(
CONVERT(VARCHAR(5) , EndEvents.dateSubmitted , 108) , @Incomplete
) AS EndTime
,COALESCE(
StartEvents.note, EndEvents.note, ''
) as [Note]
,COALESCE(
StartEvents.technician,EndEvents.technician,'Not Available'
) AS Technician
FROM
@StartEvents As StartEvents
FULL OUTER JOIN
@EndEvents AS EndEvents ON
StartEvents.technician = EndEvents.technician AND
StartEvents.businessKey = EndEvents.businessKey AND
StartEvents.activityType = EndEvents.activityType
AND convert(VARCHAR(12), StartEvents.[date], 103) = convert(VARCHAR(12), EndEvents.[date], 103)
-- WHERE
--StartEvents.[date] between @DateFrom AND @DateTo OR
--StartEvents.[dateSubmitted] between @DateFrom AND @DateTo
ORDER BY
StartEvents.Technician,
ID,ENDID
DATA:
id,activityType,beginEnd,businessKey,date,dateSubmitted,gpsLatitude,gpsLongitude,note,odometer,technician
23569,Standby,Begin,,2010-11-01 08:00:13.000,2010-11-01 08:26:45.533,34.139,-77.895,#1140,28766,barthur@fubar.com
23570,Travel,Begin,00100228002,2010-11-01 07:00:44.000,2010-11-01 08:34:15.370,35.0634,-80.7668,,18706,creneau@fubar.com
23571,Standby,End,,2010-11-01 08:30:08.000,2010-11-01 08:35:20.463,34.0918,-77.9002,#1140,28766,barthur@fubar.com
23572,Travel,Begin,00100226488,2010-11-01 08:30:41.000,2010-11-01 08:36:56.420,34.0918,-77.9002,,28766,barthur@fubar.com
23573,Travel,End,00100226488,2010-11-01 08:45:00.000,2010-11-01 08:44:15.553,34.0918,-77.9002,,28768,barthur@fubar.com
23574,OnSite,Begin,00100226488,2010-11-01 08:45:41.000,2010-11-01 09:24:23.943,34.0918,-77.9002,,0,barthur@fubar.com
23575,OnSite,End,00100226488,2010-11-01 09:30:10.000,2010-11-01 09:33:19.953,34.0918,-77.9002,,28768,barthur@fubar.com
23576,Travel,Begin,00100228137,2010-11-01 09:30:20.000,2010-11-01 09:34:57.330,34.0918,-77.9002,,28768,barthur@fubar.com
23577,Travel,End,00100228137,2010-11-01 09:45:51.000,2010-11-01 09:42:39.230,34.0918,-77.9002,,28771,barthur@fubar.com
23578,Travel,Begin,00100228138,2010-11-01 09:00:23.000,2010-11-01 09:58:22.857,34.9827,-80.5365,,18749,creneau@fubar.com
23579,OnSite,Begin,00100228137,2010-11-01 09:45:47.000,2010-11-01 10:41:10.563,34.139,-77.895,,0,barthur@fubar.com
23580,OnSite,End,00100228137,2010-11-01 10:45:43.000,2010-11-01 11:09:14.393,34.139,-77.895,,28771,barthur@fubar.com
23581,OnSite,Begin,00100228142,2010-11-01 10:45:42.000,2010-11-01 11:29:26.447,34.139,-77.895,#1015,28771,barthur@fubar.com
23582,OnSite,End,00100228142,2010-11-01 11:15:18.000,2010-11-01 11:55:28.603,34.139,-77.895,#1015,28771,barthur@fubar.com
23583,Travel,Begin,,2010-11-01 11:15:06.000,2010-11-01 11:56:01.633,34.139,-77.895,"#1142 Fuel, #1154 Tickets",28771,barthur@fubar.com
23584,Travel,End,,2010-11-01 12:00:47.000,2010-11-01 12:07:54.867,34.139,-77.895,"#1154, #1142",28774,barthur@fubar.com
23585,Travel,End,,2010-11-01 12:00:47.000,2010-11-01 12:07:55.087,34.139,-77.895,"#1154, #1142",28774,barthur@fubar.com
23586,Break,Begin,,2010-11-01 12:00:26.000,2010-11-01 12:08:06.007,34.139,-77.895,#1153,28774,barthur@fubar.com
23587,Travel,End,,2010-11-01 12:00:47.000,2010-11-01 12:08:06.040,34.139,-77.895,"#1154, #1142",28774,barthur@fubar.com
23588,Break,Begin,,2010-11-01 12:00:26.000,2010-11-01 12:08:06.070,34.139,-77.895,#1153,28774,barthur@fubar.com
23589,Travel,End,,2010-11-01 12:00:47.000,2010-11-01 12:16:02.673,34.139,-77.895,"#1154, #1142",28774,barthur@fubar.com
23590,Travel,End,,2010-11-01 12:00:47.000,2010-11-01 12:16:14.220,34.139,-77.895,"#1154, #1142",28774,barthur@fubar.com
23591,Travel,Begin,00100228000,2010-11-01 11:45:19.000,2010-11-01 12:35:46.363,35.0634,-80.7668,,18760,creneau@fubar.com
23592,Travel,Begin,00100227980,2010-11-01 13:15:14.000,2010-11-01 13:58:51.050,34.0918,-77.9002,,28774,barthur@fubar.com
23593,Travel,Begin,00100227980,2010-11-01 13:15:14.000,2010-11-01 13:59:03.830,34.0918,-77.9002,,28774,barthur@fubar.com
23594,Travel,Begin,00100227980,2010-11-01 13:15:14.000,2010-11-01 13:59:03.893,34.1594,-77.8929,,28774,barthur@fubar.com
23595,Travel,Begin,00100227980,2010-11-01 13:15:14.000,2010-11-01 13:59:03.940,34.1594,-77.8929,,28774,barthur@fubar.com
23596,Travel,Begin,00100227980,2010-11-01 13:15:14.000,2010-11-01 13:59:15.880,34.1594,-77.8929,,28774,barthur@fubar.com
23597,Travel,Begin,00100227980,2010-11-01 13:15:14.000,2010-11-01 13:59:15.927,34.2743,-77.8668,,28774,barthur@fubar.com
23598,Travel,Begin,00100227980,2010-11-01 13:15:14.000,2010-11-01 13:59:15.987,34.2743,-77.8668,,28774,barthur@fubar.com
23599,Travel,Begin,00100228166,2010-11-01 14:00:13.000,2010-11-01 14:29:45.320,35.0634,-80.7668,,18779,creneau@fubar.com
23600,Travel,End,00100227980,2010-11-01 15:15:58.000,2010-11-01 15:15:40.403,35.3414,-78.0325,,28880,barthur@fubar.com
23601,Travel,Begin,00100228205,2010-11-01 15:30:46.000,2010-11-01 15:41:41.810,35.0661,-80.8376,,18781,creneau@fubar.com
23602,OnSite,Begin,00100227980,2010-11-01 15:15:23.000,2010-11-01 15:59:45.203,35.3873,-77.9395,,28880,barthur@fubar.com
23603,OnSite,End,00100227980,2010-11-01 16:15:22.000,2010-11-01 16:06:09.150,35.3873,-77.9395,,28880,barthur@fubar.com
23604,Travel,Begin,00100228007,2010-11-01 16:15:15.000,2010-11-01 16:15:25.253,35.3873,-77.9395,,28880,barthur@fubar.com
23605,Travel,Begin,,2010-11-01 16:15:12.000,2010-11-01 16:20:49.933,35.0445,-80.8227,Return trip home,18785,creneau@fubar.com
23606,Travel,End,00100228007,2010-11-01 16:30:48.000,2010-11-01 16:26:43.360,35.3873,-77.9395,,28884,barthur@fubar.com
23607,Travel,End,,2010-11-01 17:30:14.000,2010-11-01 17:23:57.897,35.2724,-81.1577,Return trip home,18822,creneau@fubar.com
23608,OnSite,Begin,00100228007,2010-11-01 16:30:48.000,2010-11-01 18:38:32.700,35.3941,-77.994,,28880,barthur@fubar.com
23609,Travel,Begin,00100228209,2010-11-01 17:45:16.000,2010-11-01 18:39:05.683,35.3941,-77.994,,28884,barthur@fubar.com
23610,OnSite,End,00100228007,2010-11-01 17:45:52.000,2010-11-01 18:41:36.980,35.3941,-77.994,,28884,barthur@fubar.com
23611,OnSite,Begin,00100228209,2010-11-01 18:00:38.000,2010-11-01 18:42:12.763,35.3941,-77.994,,28888,barthur@fubar.com
23612,OnSite,End,00100228209,2010-11-01 18:30:44.000,2010-11-01 18:43:29.123,35.3941,-77.994,,28888,barthur@fubar.com
23613,Standby,Begin,,2010-11-01 18:30:58.000,2010-11-01 18:45:28.857,35.3941,-77.994,#1157 ergo,28888,barthur@fubar.com
23614,Standby,End,,2010-11-01 18:45:26.000,2010-11-01 18:46:01.167,35.3941,-77.994,#1157 ergo redo,28888,barthur@fubar.com
23615,Travel,Begin,,2010-11-01 18:45:24.000,2010-11-01 18:47:37.803,35.3941,-77.994,RTN,28888,barthur@fubar.com
23616,Travel,End,,2010-11-01 20:45:05.000,2010-11-01 20:34:39.433,34.139,-77.895,#1142 Fueled,28990,barthur@fubar.com
在此图像中,您会看到突出显示的行以相同的开始时间显示6个结束时间。记录14和15显示2开始,没有结束
答案 0 :(得分:2)
这是一种滥用row_number函数的方法。请查看评论以获得一些解释。
;with Seq as (
-- Create a master sequence of events
-- Trust the date column to be accurate (don't match a Begin to an earlier End)
select id, activitytype, beginend
, coalesce(businesskey, '') as businesskey -- Needed to match nulls as equal
, [date], technician, note
, row_number() over (partition by technician, businesskey, activitytype order by [date], beginend, id) as rownumber
from TimeEntry
)
select b.id as BeginID
, e.id as EndID
, coalesce(b.technician, e.technician) as Technician
, coalesce(b.businesskey, e.businesskey) as BusinessKey
, coalesce(b.activitytype, e.activitytype) as ActivityType
, coalesce(convert(char(10), b.[date], 103), 'Incomplete') as BeginDate
, coalesce(convert(char(10), e.[date], 103), 'Incomplete') as EndDate
, coalesce(convert(char(5), b.[date], 108), 'Incomplete') as BeginTime
, coalesce(convert(char(5), e.[date], 108), 'Incomplete') as EndTime
, b.note as BeginNote
, e.note as EndNote
from (select * from Seq where beginend = 'Begin') b -- Get all Begins
full outer join (select * from Seq where beginend = 'End') e -- Get all Ends
on b.technician = e.technician
and b.businesskey = e.businesskey
and b.activitytype = e.activitytype
and b.rownumber = e.rownumber - 1 -- Match a Begin with only the very next End of that type
order by coalesce(b.[date], e.[date])
, coalesce(b.id, e.id)
, coalesce(b.technician, e.technician)
, coalesce(b.businesskey, e.businesskey)
, coalesce(b.activitytype, e.activitytype)
SQL Fiddle任何人都应该想要DDL或演示。
答案 1 :(得分:1)
使用CTE和Row_Number()我想我可以回复你想要的东西。关键是只根据技术人员,businesskey,activitytype的顺序连接相邻的行来执行完整的外部。无论如何它是:
WITH EventsCTE
AS
(
select id, technician,businessKey,activityType,
CAST(date as date) As date, dateSubmitted,
beginEnd, note,
ROW_NUMBER() OVER
(Partition BY technician,
businesskey, activityType
ORDER BY dateSubmitted) as rowN
from TimeEntry
),
BeginEventsCTE
AS
(
select id, technician,businessKey,activityType,
CAST(date as date) As date,
dateSubmitted, note, rowN
from EventsCTE
WHERE beginEnd = 'Begin'
),
EndEventsCTE
AS
(
select id, technician,businessKey,
activityType, CAST(date as date) As date,
dateSubmitted, note, rowN
from EventsCTE
WHERE beginEnd = 'End'
)
SELECT B.id,
E.id As EndId,
COALESCE(B.activityType ,E.activityType ,'Not Available') AS ActivityType,
COALESCE(convert(VARCHAR(12), B.[date], 103), 'Incomplete') As EventDate,
COALESCE(convert(VARCHAR(12), E.[date], 103), 'Incomplete') As EndDate,
COALESCE(CONVERT(VARCHAR(5) , B.dateSubmitted , 108) , 'Incomplete') As StartTime,
COALESCE(CONVERT(VARCHAR(5) , E.dateSubmitted , 108) , 'Incomplete') As EndTime,
COALESCE(B.Note, E.note, '') as Note,
COALESCE(B.technician, E.technician, 'Not Available') As Technician --, B.rowN, E.rowN
FROM BeginEventsCTE B
FULL OUTER join EndEventsCTE E
ON B.technician = E.technician AND
B.businessKey = E.businessKey AND
B.activityType = E.activityType AND
B.date = E.date AND
B.rowN = E.rowN - 1
ORDER BY
COALESCE(B.Technician, E.Technician),
COALESCE(b.id,E.id)
结果如下: