Error with Between clause - sql

I'm getting the following error with this query: Between operator without And in query expression '[DateTime] BETWEEN [StartDate'.
The query and database is in Access 2010
Thank in advance for your help!
SELECT
t1.[Name],
Max(t1.[Sum3Areas]) AS [Max]
FROM (
SELECT
qryUnion.[Name]
, Year(qryUnion.[Date]) as dtYear
, DatePart("ww",[Date]) + IIF(Weekday([Date]) >= 6,1,0) as dtWeek
, SUM(qryUnion.[Amount]) as Sum3Areas
FROM (
SELECT
1 as Source,
EID As [Name],
Closed As [Amount],
DateTime As [Date]
FROM IssueTrakINNER
JOIN [DateRangeCriteria]
ON [DateTime] BETWEEN [StartDate] and [EndDate]
UNION ALL
SELECT
2 as Source,
EID AS [Name],
Completed As [Amount],
DateCompleted AS enter code here[Date]
FROM Kana
INNER JOIN [DateRangeCriteria]
ON [DateTime] BETWEEN [StartDate] and [EndDate]
UNION ALL
SELECT
3 as Source,
EID AS [Name],
Handled As [Amount],
DateTime AS [Date]
FROM Chat
INNER JOIN [DateRangeCriteria]
ON [DateTime] BETWEEN [StartDate] and [EndDate]
)
as qryUnion
GROUP BY qryUnion.[Name] , Year(qryUnion.[Date]), DatePart("ww",[Date]) + IIF(Weekday([Date]) >= 6,1,0)
) AS t1 GROUP BY t1.[Name]

Instead of using the BETWEEN operator in your JOIN...ON statement, use it in the WHERE clause.
For example:
select
...
from tableA
join tableB
on tableA.[DateTime] = tableB.[DateTime]
where tableA.[DateTime] BETWEEN #mm/dd/yyyy# AND #mm/dd/yyyy#

Related

Tuning a query converting subquery

I was trying to change an update statement where there is a subquery in the WHERE clause to a join in order to improve performance.
DDL to sample table/data
CREATE TABLE [dbo].[Table1](
[pre_plan_id] [smallint] NULL,
[pre_type_id] [smallint] NULL,
[associate_id] [smallint] NOT NULL,
[deleted] [bit] NOT NULL
)
INSERT INTO Table1
VALUES
(NULL, NULL, -32768, 0),
(1, NULL, 2, 1),
(1, NULL, 3, 0),
(NULL, NULL, 3109, 0),
(1, NULL, 3109, 1)
CREATE TABLE [dbo].[Table2](
[type_id] [smallint] NOT NULL,
[plan_id] [smallint] NOT NULL,
[associate_id] [smallint] NOT NULL,
[time_in] [smalldatetime] NOT NULL
)
INSERT INTO Table2
VALUES
(390, 31, 3109, '2009-09-02'),
(304, 32, 3109, '2010-02-05'),
(388, 31, 3109, '2010-09-24')
The query that uses a subquery:
SELECT pre_plan_id, pre_type_id FROM Table1 WHERE pre_plan_id =1
AND associate_id NOT IN
(SELECT TOP 2 associate_id
FROM Table2 WHERE time_in= '2010-09-24 00:00:00' group by associate_id order by count(*) desc)
My attempt of converting it to JOIN
SELECT pre_plan_id
FROM (SELECT pre_plan_id, pre_type_id, rn
FROM Table1 a
LEFT JOIN
( select associate_id, Row_number() over (partition by associate_id order by count(*) desc ) rn
FROM Table2
WHERE time_in= '2010-09-24 00:00:00' Group by associate_id) b
ON a.associate_id = b.associate_id where b.rn <> 1) a
where pre_plan_id = 1
However, this displays nothing while I expect two rows; and it is happening because of b.rn <> 1
I expected it would display the NULL values when it is b.rn <> 1
Any explanation for this? Any guide on better approach of tuning the query is much appreciated.
Thanks.
You can just move the subquery to the FROM clause and use LEFT JOIN:
SELECT t1.pre_plan_id, t1.pre_type_id
FROM Table1 t1 LEFT JOIN
(SELECT TOP 2 t2.associate_id
FROM Table2
WHERE t2.time_in= '2010-09-24 00:00:00'
GROUP BY associate_id
ORDER BY COUNT(*) DESC
) t2
ON t2.associate_id = t1.associate_id
WHERE t1.pre_plan_id = 1 AND t2.associate_id IS NULL;

Calculate date difference between dates in different rows of a dataset

A table looks like this :
CREATE TABLE [dbo].[HistDT](
[ID] [bigint] NULL,
[StartDtSK] [varchar](8) NULL,
[StartDt] [datetime] NULL,
[status] [nvarchar](30) NULL,
) ON [PRIMARY]
Example data set:
ID | StartDtSK | StartDt | Status |
1 20190520 20-05-2019 12:00:13 10
1 20190520 20-05-2019 10:00:00 5
1 20190414 14-04-2019 13:23:00 2
2 20190312 12-03-2019 10:03:00 10
2 20190308 08-03-2019 18:03:00 1
etc..
I need a query which will display the number of days spent in each status. That would be easy if the table i inherited had an end date. I would then calculate the datediff and pivot for column status values.
Maybe i should create a new table using ssis where i will add an EndDt column which will be the StartDt of the latest added Status.
But is there any way to do this without creating another table?
SQL Server 2008
This is not very pretty, and I haven't tested it for all use cases. I hope you can use it or find inspiration. I'm sure there is a better way :)
declare #table2 table (
[ID] [bigint] NULL,
[StartDtSK] [varchar](8) NULL,
[StartDt] [datetime] NULL,
[status] [nvarchar](30) NULL
)
insert into #table2
values
(1 , '20190520','2019-05-20 12:00:13','10'),
(1 , '20190520','2019-05-20 10:00:00','5'),
(1 , '20190414','2019-04-14 13:23:00','2'),
(2, '20190312', '2019-03-12 10:03:00', '10'),
(2 , '20190308', '2019-03-08 18:03:00', '1')
select *,DATEDIFF(dd,startdt,enddate) as TotalDAys from (
select x.ID,StartDtSK,Startdt,[Status],Enddate from (
select *,ROW_NUMBER() over(partition by id order by startdt) as rn from #table2
) x
cross apply ( select * from (select id,StartDt as Enddate,ROW_NUMBER() over(partition by id order by startdt) as rn2 from #table2 b
)f where (rn +1 = f.rn2 ) and x.id = f.id ) d
union all
select ID,StartDtSK,startdt,[Status],'9999-12-31' as Enddate from (
select *,ROW_NUMBER() over(partition by id order by startdt desc) as rn from #table2
)X where rn=1
)y
order by id,startdt
SQL Server 2008 without cross apply
This might be a bit more pretty :)
select *,DATEDIFF(dd,startdt,enddate) as TotalDAys from (
select x.ID,StartDtSK,Startdt,[Status],case when Enddate is null then '9999-12-31' else Enddate end as Enddate from (
select *,ROW_NUMBER() over(partition by id order by startdt) as rn from #table2
) x
left join (
select * from (select id,StartDt as Enddate,ROW_NUMBER() over(partition by id order by startdt) as rn2 from #table2 b
)f ) d on (rn +1 = d.rn2 ) and x.id = d.id
)y
SQL Server 2012 and above:
Is this what you want?
declare #table2 table (
[ID] [bigint] NULL,
[StartDtSK] [varchar](8) NULL,
[StartDt] [datetime] NULL,
[status] [nvarchar](30) NULL
)
insert into #table2
values
(1 , '20190520','2019-05-20 12:00:13','10'),
(1 , '20190520','2019-05-20 10:00:00','5'),
(1 , '20190414','2019-04-14 13:23:00','2')
select *,Datediff(dd,Startdt,Enddate) as TotalDays from (
select *,LAG(StartDt,1,'9999-12-31') over(partition by ID order by StartDT desc) as EndDate from #table2
)x
Insert a rule that handles current status (9999-12-31) date
Maybe LEAD function is usefull for your question.
Like this
IsNull(DateAdd(SECOND,-1,Cast(LEAD ([StartDt],1) OVER (PARTITION BY [status] ORDER BY [StartDt]) AS DATETIME)),getdate()) AS EndDate

SELECT using Correlated Sub Queries and multiple tables

I have two tables (Table1 & Table2). One including a date (tDate) column and an ID (tTillNo) column that I would like to group by. And another with values (pValue) that I would like to sum for each date and ID.
The tables can be joined using the 'tName' and 'pName' columns from each table, however the pName column may have duplicates, which I would like to include in the sum.
For the 3 sub queries I also need to include the where clauses using the 'pCode' column.
And I would like to return the columns shown here
Using the below code however returns the sub queries with incorrect totals as I am using 'MAX(a.tName)' to prevent the grouping of this field. Could anyone suggest another way of preventing this or an alternative way of going about this query?
SELECT
DATENAME(Month,a.tDate) as 'Month Name', DAY(a.tDate) as 'Day',
MONTH(a.tDate) as 'Month', YEAR(a.tDate) as 'Year', a.tTillNo,
BankedCash=(SELECT ISNULL(CAST(SUM(b.pValue) as numeric(12,2)),0)
FROM Table2 b
where MAX(a.tName)=b.pName AND pCode = 'CSH'
or pCode = 'CHQ'),
CardTransactions=(SELECT ISNULL(CAST(SUM(b.pValue) as numeric(12,2)),0)
FROM Table2 b
where MAX(a.tName)=b.pName AND b.pCode = 'CRD'),
BankingTotal=(SELECT ISNULL(CAST(SUM(b.pValue) as numeric(12,2)),0)
FROM Table2 b
where MAX(a.tName)=b.pName AND b.pCode = 'CSH' or
b.pCode = 'CHQ' or b.pCode = 'CRD')
FROM Table1 a
group by YEAR(a.tDate), MONTH (a.tDate), DATENAME(Month,a.tDate),
DAY(a.tDate), a.tTillNo
order by YEAR(a.tDate), MONTH (a.tDate), DATENAME(Month,a.tDate)
Any suggestions or article referrals would be highly appreciated. Many thanks in advance.
CREATE TABLE [dbo].[Table1](
[UniqueID] [int] IDENTITY(1,1) NOT NULL,
[tTillNo] [varchar](4) NULL,
[tName] [varchar](20) NULL,
[tDate] [datetime] NULL)
INSERT INTO Table1 (tTillNo, tName, tDate)
VALUES ('0101', '01010000001', '2018-10-30 00:00:00.000'),
('0101', '01010000002', '2018-10-30 00:00:00.000'),
('0102', '01020000001', '2018-10-30 00:00:00.000'),
('0102', '01020000002', '2018-10-30 00:00:00.000')
CREATE TABLE [dbo].[Table2](
[UniqueID] [int] IDENTITY(1,1) NOT NULL,
[pName] [varchar](20) NULL,
[pCode] [varchar](10) NULL,
[pValue] [decimal](22, 7) NULL)
INSERT INTO Table2 (pName, pCode, pValue)
VALUES ('01010000001', 'CRD', '100.0000000'),
('01010000002', 'CSH', '100.0000000'),
('01020000001', 'CHQ', '100.0000000'),
('01020000002', 'CSH', '100.0000000'),
('01020000002', 'CRD', '100.0000000'),
('01010000001', 'CSH', '100.0000000')
I think you can solve this all with a join.
select DATENAME(Month,a.tDate) as 'Month Name'
, DAY(a.tDate) as 'Day'
, MONTH(a.tDate) as 'Month'
, YEAR(a.tDate) as 'Year'
, a.tTillNo
, BankedCash=SUM(case when pCode in( 'CSH','CHQ') then pvalue else 0 end)
, [Card] = SUM(case when pCode in( 'CRD') then pvalue else 0 end)
,Total = SUM(pvalue)
from TableA a
join TableB b on a.tName=b.pName
group by YEAR(a.tDate)
, MONTH (a.tDate)
, DATENAME(Month,a.tDate)
, DAY(a.tDate)
, a.tTillNo

SQL - condition on a timestampdiff

I would like to get the average time of solution time for tickets
from state 'billet ouvert' to state 'résolu'.
Table Sample
The queries I tried:
Query 1:
SELECT
title AS 'Etat', ticket_id, user_id,
AVG(TIMESTAMPDIFF(HOUR,
helpdesk_followup.date having title in ('billet ouvert'),
helpdesk_followup.date having title in ('résolu'))
) AS 'moyenne'
FROM helpdesk_followup
GROUP BY user_id;
Query 2:
SELECT
title AS 'Etat', ticket_id, user_id,
AVG(TIMESTAMPDIFF(HOUR,
helpdesk_followup.date as date1,
helpdesk_followup.date as date2)
) AS 'moyenne'
FROM helpdesk_followup
WHERE date1 having title IN 'résolu'
AND date2 having title IN 'billet ouvert'
GROUP BY user_id;
But these queries doesn't get the result I need. How can I add condition to a timestampdiff?
The first column is the starting event and the second column is the end event.
I have done the average in minutes. This SQL works off the title which you may wish to tweak to something more distinct
select a.title, b.title, avg(DateDiff(MINUTE, '00:00:00', b.[date] ) - DateDiff(MINUTE, '00:00:00', a.[date] ) ) from
(select *, row_number() over (order by [date]) hf from helpdesk_followup) a
join (select *, row_number() over (order by [date]) hf from helpdesk_followup) b on (a.hf=b.hf-1)
group by
a.title, b.title
I have left out the user_id from the query as I'm unsure if you wish to break it down using that field.
Hopefully its a start for you to amend into what you need
EDIT: Here is the test data I used for the query
CREATE TABLE [dbo].[helpdesk_followup](
[title] [varchar](50) NULL,
[ticket_id] [int] NULL,
[user_id] [int] NULL,
[date] [datetime] NULL
) ON [PRIMARY]
GO
SET ANSI_PADDING OFF
GO
INSERT [dbo].[helpdesk_followup] ([title], [ticket_id], [user_id], [date]) VALUES (N'billet ouvert', 133, NULL, CAST(N'2015-07-22 15:36:00.000' AS DateTime))
GO
INSERT [dbo].[helpdesk_followup] ([title], [ticket_id], [user_id], [date]) VALUES (N'résolu', 133, 19, CAST(N'2015-07-23 15:36:00.000' AS DateTime))
GO
INSERT [dbo].[helpdesk_followup] ([title], [ticket_id], [user_id], [date]) VALUES (N'billet ouvert', 134, 15, CAST(N'2015-07-23 15:36:00.000' AS DateTime))
GO
INSERT [dbo].[helpdesk_followup] ([title], [ticket_id], [user_id], [date]) VALUES (N'résolu', 134, 21, CAST(N'2015-07-27 15:36:00.000' AS DateTime))
GO

T-SQL join to get both mated and non mated start and stop records

I have a poorly designed table that I did not design and cannot fix/change because a 3rd party blackberry app that writes to it. The meat is that there is a start record and a stop record for tracking events with NO connection or validation that there is a match. The blackberry app does nothing to tie these records together. I have tried to create a join on its self and create temp tables with the begin and one with the end to full outer join them. The problem is that I have duplicate entries were the entry should be marked as having no mate. Existing data has rows with no mate on both the start and end records. I have searched SO for answers and I found some close answers that have led me this far. I know its a long post, sorry for that.
There is a single table that surprisingly has a primary key. There is no pivot/intersection table. Structure is
ID (int PK)
activityType varchar
beginEnd varchar ('begin' or 'end')
businessKey varchar nullable
date DATETIME
technician varchar
The following columns are in the table as well, but are nullable, and not important to the query.
dateSubmitted DATETIME
gpsLatitude float
gpsLongitude float
note varchar
odometer int
The query that I have now that still leaves dupes: Showing and sorting ID and EndID are for debugging only
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
In this image you see that the highlighted rows are showing 6 end times with the same begin times. and records 14 and 15 show 2 begins and no ends.
Here is a method which abuses the row_number function. Please check the comments for some explanation.
;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)
And the SQL Fiddle should anyone want the DDL or demo.
Using CTE's and Row_Number() I think I can return what you are looking for. The key is to only perform your full outer by joining on adajacent rows based upon an ordering of technician, businesskey, activitytype. Anyway here it is:
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)
And here's the results: