Select all from primary table, join to others - sql
I am hoping somebody can help me. If I do a standard Inner Join or right join, i get very few results. Would also be great to also know why what I am trying wont work.
I have a primary Table of members. MemberID is common to all tables
Select * from apf_members
MemberID--|--AppsTitle--|--AppsFirstName--|--AppsLastName--
2015 Mrs Naomi Specter
2016 Mr Marisa Watson
2025 Mr Elia Barker
2031 Dr Heth Rowing
2044 Ms Kathryn McKenzie
I also want to attached 3 extra columns that are dynamically built.
--CurrentMember--|--UnrenewedMember--|--LapsedMember--
The queries below will currently return the value only ~IF~ the user has a record. where I need it to return a NULL or an empty string.
#theDate is a variable, ill assign it to Getdate for now.
Declare #theDate date
SET #theDate = GetDate()
Select Description as 'CurrentMember' from apf_finances
where #theDate between StartDate and EndDate
and Status = 'Financial Status'
Select Description as 'UnrenewedMember'
from apf_finances
where #theDate between DATEADD(year, -1, StartDate) and DATEADD(year, -1, EndDate)
and Status = 'Financial Status'
Select Description as 'LapsedMember'
from apf_finances
where #theDate between DATEADD(year, -2, StartDate) and DATEADD(year, -2, EndDate)
and Status = 'Financial Status'
Put together,final result would look like this.
MemberID--|--AppsTitle--|--AppsFirstName--|--AppsLastName--|--CurrentMember--|--UnrenewedMember--|--LapsedMember--
2015 Mrs Naomi Specter f nf nf
2016 Mr Marisa Watson uf NULL nf
2025 Mr Elia Barker NULL NULL NULL
2031 Dr Heth Rowing co exp f
2044 Ms Kathryn McKenzie NULL f NULL
*UPDATE 22/10/2013 *
here is a SQL script that should re-create the tables
CREATE TABLE [dbo].[apf_Members](
[MemberID] [int] IDENTITY(1,1) NOT NULL,
[AppsTitle] [nvarchar](50) NULL,
[AppsFirstName] [nvarchar](50) NULL,
[AppsMiddleName] [nvarchar](50) NULL,
[AppsLastName] [nvarchar](50) NULL,
)
GO
CREATE TABLE [dbo].[apf_Finances](
[ID] [int] IDENTITY(1,1) NOT NULL,
[MemberID] [int] NOT NULL,
[Description] [nvarchar](50) NULL,
[StartDate] [date] NULL,
[EndDate] [date] NULL,
[Status] [nvarchar](50) NULL
)
GO
SET IDENTITY_INSERT dbo.[apf_Members] ON
GO
SET IDENTITY_INSERT dbo.[apf_Finances] ON
GO
INSERT INTO [dbo].[apf_Members]
([MemberID],[AppsTitle],[AppsFirstName],[AppsLastName])
VALUES (2015,'Mrs','Naomi', 'Specter' ),
(2016 , 'Mr' ,'Marisa','Watson' ),
(2025 , 'Mr' ,'Elia','Barker'),
(2031 , 'Dr','Heth','Rowing'),
(2044 , 'Ms','Kathryn','McKenzie');
INSERT INTO [apf_Finances]
([ID], [MemberID], [Description], [StartDate], [EndDate], [Status] )
VALUES
(12381, 2016, 'f' ,'2013-10-15','2014-10-14','Financial Status'),
(12382, 2016, '' ,'2013-10-15','2014-10-14','Donation'),
(12361, 2025, 'f' ,'2013-10-12','2014-10-11','Financial Status'),
(12362, 2025, '' ,'2013-10-12','2014-10-11','Donation'),
(12357, 2031, 'f' ,'2013-10-11','2014-10-10','Financial Status'),
(12358, 2031, '' ,'2013-10-11','2014-10-10','Donation'),
(12379, 2044, 'f' ,'2012-10-21','2013-10-20','Financial Status'),
(12380, 2044, '' ,'2012-10-21','2013-10-20','Donation'),
(12377, 2016, 'f' ,'2012-10-17','2013-10-16','Financial Status'),
(12378, 2016, '' ,'2012-10-17','2013-10-16','Donation'),
(12373, 2025, 'f' ,'2012-10-16','2013-10-15','Financial Status'),
(12374, 2031, '' ,'2011-10-16','2013-10-15','Donation'),
(12375, 2031, 'f' ,'2011-10-16','2013-10-15','Financial Status'),
(12376, 2044, '' ,'2011-10-16','2013-10-15','Donation'),
(12371, 2044, 'f' ,'2011-10-15','2013-10-14','Financial Status');
Here is a Northwind example.
You can "filter" by using derived tables.
And then left join on the derived table(s).
You can write yours, and you'll have 3 derived tables.
derivedCurrentMember
derivedUnrenewedMember
derivedLapsedMember
Put your filtering/logic in each derived table. Then left join on each one.
Here is a generic Northwind example.
My "filtering logic" is whether a discount existed or not. (innerOd1.Discount <=0 and innerOd1.Discount > 0). You may not need the group-by.
Use Northwind
GO
Select ords.OrderID
, ISNULL ( derived1.MyCount , 0) as NoDiscountCount
, ISNULL ( derived2.MyCount , 0) as HasDiscountCount
from dbo.Orders ords
left join
( select innerOd1.OrderID , count (*) as MyCount from dbo.[Order Details] innerOd1 where innerOd1.Discount <=0 group by innerOd1.OrderID) derived1
on ords.OrderID = derived1.OrderID
left join
( select innerOd2.OrderID , count (*) as MyCount from dbo.[Order Details] innerOd2 where innerOd2.Discount > 0 group by innerOd2.OrderID) derived2
on ords.OrderID = derived2.OrderID
order by ords.OrderID
::: APPEND :::
Here is the first one.
You can fill in the rest.
declare #theDate datetime
select #theDate = getdate()
select membs.* , currentMemberDerived.[CurrentMember] from
[dbo].[apf_Members] membs
left join
(
Select MemberID , [Description] as 'CurrentMember' from apf_finances
where #theDate between StartDate and EndDate
and Status = 'Financial Status'
) currentMemberDerived
on membs.MemberID = currentMemberDerived.MemberID
Related
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
Insert a constant value to table in stored procedure
I have the following stored procedure: DECLARE #BeginDate1 datetime, #EndDate1 datetime set #BeginDate1 = '04-01-2012' set #EndDate1 = '03-31-2013' BEGIN INSERT INTO MTBUR_Type_Stage SELECT R.Type, [Hours], LEFT(dbo.fn_GetPartName(R.PartID),CHARINDEX('-',dbo.fn_GetPartName(R.ACSS_PartID), 1) - 1) AS 'Part No', Count(s.status) AS NumberUnscheduled, ([Hours]/Count(s.status)) AS MTBUR FROM Repair R INNER JOIN Conversion C ON (R.Performed = C.Performed) AND (R.Confirmed = C.Confirmed) INNER JOIN Status S ON C.StatusID = S.StatusID INNER JOIN #MTBUR_Hrs_Temp TEMP ON LEFT(dbo.fn_GetPartName(R.PartID),CHARINDEX('-',dbo.fn_GetPartName(R.PartID), 1) - 1) = TEMP.productNo AND R.Type = TEMP.Type WHERE (R.Received BETWEEN #BeginDate1 AND #EndDate1) AND (S.Status = 'UNSCHEDULED') GROUP BY LEFT(dbo.fn_GetPartName(R.PartID),CHARINDEX('-',dbo.fn_GetPartNaame(R.PartID), 1) - 1), [Hours], R.Type ORDER BY R.Type, LEFT(dbo.fn_GetPartName(R.ACSS_PartID),CHARINDEX('-',dbo.fn_GetPartID(R.PartID), 1) - 1) ASC DROP TABLE #MTBUR_Hrs_Temp END The table being inserted to (MTBUR_Type_Stage) has columns named EndingDate and EndingQuarter. EndingDate needs to have the same date (constant) which is equal to #EndDate and EndingQuarter needs to have a constant value of 1 How can I script this in my stored procedure so that ALL rows are populated with these constants in the relevant columns in MTBUR_Type_Stage are populated with these constants? The following is the DDL for the table I am inserting into: CREATE TABLE [dbo].[MTBUR_ByType_StageTbl] ( [Type] [nvarchar](25) NULL, [Hours] [float] NULL, [Part No] [varchar](15) NULL, [UnscheduledRemovals] [int] NULL, [MTBUR] [float] NULL, [EndingDate] [datetime] NULL, [EndingQuarter] [int] NULL ) ON [PRIMARY]
As simple as this: insert MTBUR_Type_Stage(EndingDate,EndingQuarter) values (#EndDate,1) ; or this insert MTBUR_Type_Stage(EndingDate,EndingQuarter) select #EndDate,1 Expanded for more fields: insert MTBUR_Type_Stage( [Type], [Hours], [Part No], [UnscheduledRemovals], [MTBUR], [EndingDate], [EndingQuarter] [int] NULL ) select 'x',1.00,'part 1', 0, 2.34, #EndDate,1
SQL Aggregate Function Query not Producing Expected Results
The following is my query to go through about a million rows to calculate MTBUR (Mean Time Before Unscheduled Repair): DECLARE #BeginDate date = '01-01-2013', #EndDate date = '12-31-2013' BEGIN SELECT H.AutoType, COALESCE(((SUM(H.Hours))/(CASE WHEN R.ReceivedDate BETWEEN #BeginDate AND #EndDate THEN COUNT(R.Confirmed) END)), SUM(H.Hours)) AS 'MTBUR' FROM Hours H INNER JOIN Repair R ON H.SN = R.SN WHERE (R.Confirmed NOT LIKE 'C%' AND R.Confirmed NOT LIKE 'O%') AND (H.Date BETWEEN #BeginDate AND #EndDate) GROUP BY H.AutoType, R.ReceivedDate END The following are example results for 2 types: Type | MTBUR ------------ a | value a | value a | value b | value b | value b | value I want my results to look like this: Type | MTBUR ------------ a | value b | value Why is it grouping the same type several times. I want only 1 value for each type. Also, Why is the DBMS making me also group by ReceivedDate? I get the feeling that is screwing my results up. Any suggestions? The following are my CREATE TABLE: CREATE TABLE [dbo].[acss_hours]( [hoursId] [uniqueidentifier] NOT NULL, [name] [nvarchar](100) NULL, [Type] [nvarchar](100) NULL, [SN] [nvarchar](100) NULL, [Reg] [nvarchar](100) NULL, [Hours] [float] NULL, [Date] [datetime] NULL) CREATE TABLE [dbo].[repair]( [repairId] [uniqueidentifier] NOT NULL, [Part] [nvarchar](100) NULL, [Customer] [nvarchar](100) NULL, [AutoType] [nvarchar](100) NULL, [ReceivedDate] [datetime] NULL, [Confirmed] [nvarchar](100) NULL, [Company] [nvarchar](100) NULL, [Reg] [nvarchar](100) NULL, [Manu] [nvarchar](100) NULL, [SN] [nvarchar](100) NULL)
You are correct, adding ReceivedDate is screwing up your results. You are getting one row for each type for RecievedDate. SQL Server if forcing you to add RecievedDate to the group by because you are using it in the select clause. When SQL Server processes each AutoType, what ReceivedDate should it use? It has multiple ReceivedDates per AutoType. Either it needs to use each seperate ReceivedDate by adding it to the group by, or it can use a aggregate function like min or max to select one of the RecievedDates. How do you want your query to handle it? I think you should wrap your case in the COUNT. COUNT(CASE WHEN R.ReceivedDate BETWEEN #BeginDate AND #EndDate THEN R.Confirmed ELSE 0 END)
You need to include R.ReceivedDate from your calculation in the group by because you're evaluating the column with the between statement. Its the same as including the column in the select. Basically any column in the select line that doesn't have an aggregation function needs to be in the group by.
You will have to make use of the keyword DISTINCT. So effectively, you can query as such: DECLARE #BeginDate date = '01-01-2013', #EndDate date = '12-31-2013' BEGIN SELECT DISTINCT H.AutoType, COALESCE(((SUM(H.Hours))/(CASE WHEN R.ReceivedDate BETWEEN #BeginDate AND #EndDate THEN COUNT(R.Confirmed) END)), SUM(H.Hours)) AS 'MTBUR' FROM Hours H INNER JOIN Repair R ON H.SN = R.SN WHERE (R.Confirmed NOT LIKE 'C%' AND R.Confirmed NOT LIKE 'O%') AND (H.Date BETWEEN #BeginDate AND #EndDate) GROUP BY H.AutoType, R.ReceivedDate END Hope this helps!!!
Didn't let me post this in the comment. Try an inner query: SELECT H.AutoType, COALESCE(((SUM(H.Hours))/(SUM(x.CountConfirmed))), SUM(H.Hours)) AS 'MTBUR' FROM (SELECT H.AutoType, CASE WHEN R.ReceivedDate BETWEEN #BeginDate AND #EndDate THEN 1 ELSE 0 END AS CountConfirmed FROM Hours H INNER JOIN Repair R ON H.SN = R.SN WHERE (R.Confirmed NOT LIKE 'C%' AND R.Confirmed NOT LIKE 'O%') AND (H.Date BETWEEN #BeginDate AND #EndDate)) x JOIN Hours H ON H.AutoType = x.AutoType WHERE (H.Date BETWEEN #BeginDate AND #EndDate) GROUP BY H.AutoType
Pivot data issue how can group this data in SQL Server 2008 R2
I have been looking at the Pivot function in SQL Server 2008 R2. I would like to achieve the following results OrderName Processed NotProcessed OrderDescription Pasta 1 1 Pasta Order Fruit 2 1 Fruit Order Meat 2 1 Meat Order I have tried to use a pivot but my column OrderName is a varchar . This is the table and data: IF OBJECT_ID(N'[dbo].[OrderSummary]','U') IS NOT NULL DROP TABLE [dbo].[OrderSummary] CREATE TABLE [dbo].[OrderSummary] ( [Id] [bigint] IDENTITY(1,1) NOT NULL, [OrderNo] [varchar](10) NOT NULL, [OrderStatus] [varchar](50) NOT NULL, [Category] [varchar](50) NOT NULL, [OrderName] [varchar](255) NOT NULL, [OrderDescription] [varchar](350) NOT NULL, CONSTRAINT [PK_OrderSummary] PRIMARY KEY CLUSTERED ([Id] ASC) ) ON [PRIMARY] GO SET IDENTITY_INSERT [dbo].[OrderSummary] ON; BEGIN TRANSACTION; INSERT INTO [dbo].[OrderSummary]([Id], [OrderNo], [OrderStatus], [Category], [OrderName], [OrderDescription]) SELECT 1, N'100', N'Processed', N'Pasta', N'PastaOrder', N'Pasta Order' UNION ALL SELECT 2, N'101', N'Processed', N'Fruit', N'FruitOrder', N'Fruit Order' UNION ALL SELECT 3, N'102', N'NotProcessed', N'Meat', N'MeatOrder', N'Meat Order' UNION ALL SELECT 5, N'103', N'NotProcessed', N'Pasta', N'PastaOrder', N'Pasta Order' UNION ALL SELECT 6, N'104', N'Processed', N'Fruit', N'FruitOrder', N'Fruit Order' UNION ALL SELECT 8, N'105', N'NotProcessed', N'Meat', N'MeatOrder', N'Meat Order' UNION ALL SELECT 9, N'106', N'Processed', N'Meat', N'MeatOrder', N'Meat Order' UNION ALL SELECT 10, N'107', N'NotProcessed', N'Fruit', N'FruitOrder', N'Fruit Order' COMMIT; GO SET IDENTITY_INSERT [dbo].[OrderSummary] OFF; Any suggestions? Will create a sql fiddle if it makes easier.
The following query gives the required result: SELECT OrderName ,SUM(CASE WHEN OrderStatus = 'Processed' THEN 1 ELSE 0 END) AS Processed ,SUM(CASE WHEN OrderStatus = 'NotProcessed' THEN 1 ELSE 0 END) AS NotProcessed ,OrderDescription FROM OrderSummary GROUP BY OrderName, OrderDescription
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: