September 6, 2015 at 4:34 am
Dear all,
I can't figure this Problem out:
I have a table like the following (with much more data, but the concept is the same) with Dates and Actions for People and a column called Action with beginning Dates and end dates.
(I attached a picture because I could not figure out how to Format it)
begin Date end Date Name
begin 2014-10-15 end 2014-10-31 phil
begin 2014-09-18 end 2014-09-30 phil
begin 2014-08-21 end 2014-08-23 John
I need the query to be like this. The idea is to have the query grab the next 'END' not all Ends, which my attempts have done i.e. I get not just the closest end to the begin date, but ALL Ends with the same Person.
I Need it to look like this:
begin Date end Date Name
begin 2014-10-15 end 2014-10-31 phil
begin 2014-09-18 end 2014-09-30 phil
begin 2014-08-21 end 2014-08-23 John
There can be different People so the query Needs to return the beginning and end rows for the Person in sequential order.
Any help is greatly appreciated. I can't figure out how to select only the 'next' end. My query always gets 'end' values that have a 'begin'. Is this possible? Hope this makes sense.
Thanks for any help.
September 6, 2015 at 6:48 am
Quick solution
😎
USE tempdb;
GO
SET NOCOUNT ON;
GO
DECLARE @SAMPLE_DATA TABLE
(
[action] VARCHAR(10) NOT NULL
,[date] DATE NOT NULL
,[Name] VARCHAR(25) NOT NULL
);
INSERT INTO @SAMPLE_DATA([action],[date] ,[Name])
VALUES ('end' ,'2014-10-31','phil')
,('begin' ,'2014-10-15','phil')
,('end' ,'2014-09-30','phil')
,('begin' ,'2014-09-18','phil')
,('end' ,'2014-08-23','John')
,('begin' ,'2014-08-21','John')
;
;WITH BASE_DATA AS
(
SELECT
ROW_NUMBER() OVER
(
PARTITION BY SD.[Name]
ORDER BY SD.[date]
) - CASE
WHEN SD.[action] = 'end' THEN 1
ELSE 0
END AS RID
,SD.[action]
,SD.[date]
,SD.[Name]
FROM @SAMPLE_DATA SD
)
SELECT
MAX(CASE WHEN BD.[action] = 'begin' THEN BD.[action] END) AS [begin]
,MAX(CASE WHEN BD.[action] = 'begin' THEN BD.[date] END) AS [Date]
,MAX(CASE WHEN BD.[action] = 'end' THEN BD.[action] END) AS [end]
,MAX(CASE WHEN BD.[action] = 'end' THEN BD.[date] END) AS [Date]
,BD.[Name]
FROM BASE_DATA BD
GROUP BY BD.[Name]
,BD.RID
ORDER BY BD.[Name] DESC
,BD.RID DESC;
Results
begin Date end Date Name
---------- ---------- ---------- ---------- -----
begin 2014-10-15 end 2014-10-31 phil
begin 2014-09-18 end 2014-09-30 phil
begin 2014-08-21 end 2014-08-23 John
September 6, 2015 at 7:40 am
Many thanks!
This worked, but I made a temp table for the first part. TBH, I am fairly new to SQL and do not understand the beginning part:
;
;WITH BASE_DATA AS
(
SELECT
ROW_NUMBER() OVER
(
PARTITION BY SD.[Name]
ORDER BY SD.[date] ........Etc....
I was getting some errors since maybe I do not Need to create a table. I made a temp table and then queried it. What exactly is the first select Statement I have never seen that before?
Either way this works fantastically. Thank you, seriously!
September 6, 2015 at 7:54 am
One more question...
If I wanted to get a DATEDIFF between the two Dates, how would I accomplish that? Many thanks.
September 6, 2015 at 8:07 am
Here is the code again with comments, let me know if you need further explanation.
😎
/* CTE (Common Table Expression for marking the sessions in
chronological order, creating an identifier for each pair
of begin/end. It makes the assumption that there will
always be a beginning and an end for each party.
*/
;WITH BASE_DATA AS
(
SELECT
/* The ROW_NUMBER "counts" the instances of each party
and subtracs one from each "end". The result is a
group identifier of odd numbers, each value unique
for each session.
*/
ROW_NUMBER() OVER
(
PARTITION BY SD.[Name]
ORDER BY SD.[date]
) - CASE
WHEN SD.[action] = 'end' THEN 1
ELSE 0
END AS RID
,SD.[action]
,SD.[date]
,SD.[Name]
FROM @SAMPLE_DATA SD
)
/* Simple cross-tab to transpose/pivot the results to the
desired format. The group identifier is necessary in order
not to compress/pack the sessions, without it there would
only be one session per party
*/
SELECT
MAX(CASE WHEN BD.[action] = 'begin' THEN BD.[action] END) AS [begin]
,MAX(CASE WHEN BD.[action] = 'begin' THEN BD.[date] END) AS [Date]
,MAX(CASE WHEN BD.[action] = 'end' THEN BD.[action] END) AS [end]
,MAX(CASE WHEN BD.[action] = 'end' THEN BD.[date] END) AS [Date]
,BD.[Name]
FROM BASE_DATA BD
GROUP BY BD.[Name]
,BD.RID
ORDER BY BD.[Name] DESC
,BD.RID DESC;
September 6, 2015 at 8:10 am
g7u (9/6/2015)
One more question...If I wanted to get a DATEDIFF between the two Dates, how would I accomplish that? Many thanks.
Simply add it to the last part of the query
😎
;WITH BASE_DATA AS
(
SELECT
/* The ROW_NUMBER "counts" the instances of each party
and subtracs one from each "end". The result is a
group identifier of odd numbers, each value unique
for each session.
*/
ROW_NUMBER() OVER
(
PARTITION BY SD.[Name]
ORDER BY SD.[date]
) - CASE
WHEN SD.[action] = 'end' THEN 1
ELSE 0
END AS RID
,SD.[action]
,SD.[date]
,SD.[Name]
FROM @SAMPLE_DATA SD
)
/* Simple cross-tab to transpose/pivot the results to the
desired format. The group identifier is necessary in order
not to compress/pack the sessions, without it there would
only be one session per party
*/
SELECT
MAX(CASE WHEN BD.[action] = 'begin' THEN BD.[action] END) AS [begin]
,MAX(CASE WHEN BD.[action] = 'begin' THEN BD.[date] END) AS [Date]
,MAX(CASE WHEN BD.[action] = 'end' THEN BD.[action] END) AS [end]
,MAX(CASE WHEN BD.[action] = 'end' THEN BD.[date] END) AS [Date]
,DATEDIFF(DAY,MAX(CASE WHEN BD.[action] = 'begin' THEN BD.[date] END)
,MAX(CASE WHEN BD.[action] = 'end' THEN BD.[date] END)) AS DURATION
,BD.[Name]
FROM BASE_DATA BD
GROUP BY BD.[Name]
,BD.RID
ORDER BY BD.[Name] DESC
,BD.RID DESC;
Results
begin Date end Date DURATION Name
---------- ---------- ---------- ---------- ----------- ------
begin 2014-10-15 end 2014-10-31 16 phil
begin 2014-09-18 end 2014-09-30 12 phil
begin 2014-08-21 end 2014-08-23 2 John
September 6, 2015 at 8:56 am
I really can't thank you enough. Thank you for the superb help and explanation. This was stumping me for quite some time.
September 6, 2015 at 9:19 am
g7u (9/6/2015)
I really can't thank you enough. Thank you for the superb help and explanation. This was stumping me for quite some time.
You are very welcome and thank you for the feedback;-)
😎
September 8, 2015 at 4:15 am
SELECT a.action as [begin],a.date,b.action as [end],b.date,a.Name
FROM(
SELECT * , ROW_NUMBER()OVER (order by action,date desc) as row_Num
FROM #SAMPLE_DATA
WHERE action='begin'
)a
INNER JOIN
(SELECT * , ROW_NUMBER()OVER (order by action,date desc) as row_Num
FROM #SAMPLE_DATA
WHERE action='end')b
ON a.row_Num=b.row_Num
Viewing 9 posts - 1 through 8 (of 8 total)
You must be logged in to reply to this topic. Login to reply