;with cte as
(
select FingerId, [Date],
LogTime,
row_number() over(partition by FingerId order by LogTime) as rn
from InOut
)
select C3.EmployeeName,C1.FingerId,
C1.LogTime as InTime,
C2.LogTime as OutTime,
C2.[Date]
from cte as C1
left outer join cte as C2
on C1.FingerId = C2.FingerId and
C1.rn + 1 = C2.rn INNER JOIN
EmployeeMaster as C3 ON C3.Fingerid = C2.Fingerid
where C1.rn % 2 = 1 and C3.EmployeeName = 'xyz' and C1.[Date] between '2011-07-21' and '2011-07-29' order by C2.[Date]
select * From Inout order by LogTime asc
I am having INOUT Table It have 5 record and 3 record is of 2011-07-2011
InOuT Table:
AutoId FingerId LogTime Date
1 22 11:18:48 AM 2011-07-29
2 22 11:19:54 AM 2011-07-29
3 22 11:20:50 AM 2011-07-21
4 22 11:21:54 AM 2011-07-21
5 22 11:21:59 AM 2011-07-21
I am getting this output by this above query
EmployeeName FingerId InTime OutTime Date
xyz 22 11:20:50 AM 11:21:54 AM 2011-07-21
xyz 22 11:18:48 AM 11:19:54 AM 2011-07-29
I Want this type of OutPut:-
EmployeeName FingerId InTime OutTime Date
xyz 22 11:20:50 AM 11:21:54 AM 2011-07-21
xyz 22 11:21:59 AM ---- 2011-07-21
xyz 22 11:18:48 AM 11:19:54 AM 2011-07-29
Here 2nd row is having InTime and i want outtime should display "---" dash.But i m not getting with this query. Query is correct but need to do modify for this.
I've made some modifications to your query which I'm posting now with the changes highlighted in bold:
;WITH cte AS
(
SELECT FingerId, [Date],
LogTime,
ROW_NUMBER() OVER(PARTITION BY FingerId ORDER BY LogTime) AS rn
FROM InOut
)
SELECT C3.EmployeeName,C1.FingerId,
C1.LogTime AS InTime,
C2.LogTime AS OutTime,
COALESCE(C2.[Date], C1.[Date]) AS Date
FROM cte AS C1
LEFT OUTER JOIN cte AS C2 ON C1.FingerId = C2.FingerId AND C1.rn + 1 = C2.rn
INNER JOIN EmployeeMaster AS C3 ON C3.Fingerid = C1.Fingerid
WHERE C1.rn % 2 = 1
AND C3.EmployeeName = 'xyz'
AND C1.[Date] BETWEEN '2011-07-21' AND '2011-07-29'
ORDER BY C1.[Date]
Originally I was thinking about changing C1.[Date] in the SELECT clause to C2.[Date], but then I wasn't sure it would be quite adequate a replacement in case the two dates were different. You can see for yourself which option is better, if any.
You'll have to use C1.[Date] instead of C2.[Date] in your WHERE clause - since you are outer joining to C2 and the row you are missing has a NULL value for C2.[Date].
Related
I have bunch of data out of which I'm showing ID, max date and it's corresponding values (user id, type, ...). Then I need to take MAX date for each ID, substract 30 days and show first date and it's corresponding values within this date period.
Example:
ID Date Name
1 01.05.2018 AAA
1 21.04.2018 CCC
1 05.04.2018 BBB
1 28.03.2018 AAA
expected:
ID max_date max_name previous_date previous_name
1 01.05.2018 AAA 05.04.2018 BBB
I have working solution using subselects, but as I have quite huge WHERE part, refresh takes ages.
SUBSELECT looks like that:
(SELECT MIN(N.name)
FROM t1 N
WHERE N.ID = T.ID
AND (N.date < MAX(T.date) AND N.date >= (MAX(T.date)-30))
AND (...)) AS PreviousName
How'd you write the select?
I'm using TSQL
Thanks
I can do this with 2 CTEs to build up the dates and names.
SQL Fiddle
MS SQL Server 2017 Schema Setup:
CREATE TABLE t1 (ID int, theDate date, theName varchar(10)) ;
INSERT INTO t1 (ID, theDate, theName)
VALUES
( 1,'2018-05-01','AAA' )
, ( 1,'2018-04-21','CCC' )
, ( 1,'2018-04-05','BBB' )
, ( 1,'2018-03-27','AAA' )
, ( 2,'2018-05-02','AAA' )
, ( 2,'2018-05-21','CCC' )
, ( 2,'2018-03-03','BBB' )
, ( 2,'2018-01-20','AAA' )
;
Main Query:
;WITH cte1 AS (
SELECT t1.ID, t1.theDate, t1.theName
, DATEADD(day,-30,t1.theDate) AS dMinus30
, ROW_NUMBER() OVER (PARTITION BY t1.ID ORDER BY t1.theDate DESC) AS rn
FROM t1
)
, cte2 AS (
SELECT c2.ID, c2.theDate, c2.theName
, ROW_NUMBER() OVER (PARTITION BY c2.ID ORDER BY c2.theDate) AS rn
, COUNT(*) OVER (PARTITION BY c2.ID) AS theCount
FROM cte1
INNER JOIN cte1 c2 ON cte1.ID = c2.ID
AND c2.theDate >= cte1.dMinus30
WHERE cte1.rn = 1
GROUP BY c2.ID, c2.theDate, c2.theName
)
SELECT cte1.ID, cte1.theDate AS max_date, cte1.theName AS max_name
, cte2.theDate AS previous_date, cte2.theName AS previous_name
, cte2.theCount
FROM cte1
INNER JOIN cte2 ON cte1.ID = cte2.ID
AND cte2.rn=1
WHERE cte1.rn = 1
Results:
| ID | max_date | max_name | previous_date | previous_name |
|----|------------|----------|---------------|---------------|
| 1 | 2018-05-01 | AAA | 2018-04-05 | BBB |
| 2 | 2018-05-21 | CCC | 2018-05-02 | AAA |
cte1 builds the list of max_date and max_name grouped by the ID and then using a ROW_NUMBER() window function to sort the groups by the dates to get the most recent date. cte2 joins back to this list to get all dates within the last 30 days of cte1's max date. Then it does essentially the same thing to get the last date. Then the outer query joins those two results together to get the columns needed while only selecting the most and least recent rows from each respectively.
I'm not sure how well it will scale with your data, but using the CTEs should optimize pretty well.
EDIT: For the additional requirement, I just added in another COUNT() window function to cte2.
I would do:
select id,
max(case when seqnum = 1 then date end) as max_date,
max(case when seqnum = 1 then name end) as max_name,
max(case when seqnum = 2 then date end) as prev_date,
max(case when seqnum = 2 then name end) as prev_name,
from (select e.*, row_number() over (partition by id order by date desc) as seqnum
from example e
) e
group by id;
I am working on to adjust overlapping date in database tables.
Sample data as below
StartDate EndDate UNIT ID
2017-06-09 2017-06-22 1A 21
2017-06-09 2017-06-30 1B 21
2017-07-01 2017-07-31 1B 21
Expected output:
StartDate EndDate UNIT ID
2017-06-09 2017-06-22 1A 21
2017-06-22 2017-06-30 1B 21
2017-07-01 2017-07-31 1B 21
appreciate your help on this.
You can use lead/lag in case of 2012+, since your are using 2008 you can query as below:
;With cte as (
Select *, RowN = Row_Number() over(partition by Id order by EndDate ) from #sampledata
)
Select StartDate = Coalesce (Case when Dateadd(DD, 1, c2.Enddate) = c1.Startdate then c1.Startdate Else c2.Enddate End, c1.StartDate)
,c1.Enddate, c1.Unit, C1.Id
from cte c1 left join cte c2
on c1.RowN = c2.RowN+1
If you still do not want to use cte as above then you can do sub-query as below:
Select StartDate = Coalesce (Case when Dateadd(DD, 1, c2.Enddate) = c1.Startdate then c1.Startdate Else c2.Enddate End, c1.StartDate)
,c1.Enddate, c1.Unit, C1.Id
from (Select *, RowN = Row_Number() over(partition by Id order by EndDate ) from #sampledata ) c1
left join (Select *, RowN = Row_Number() over(partition by Id order by EndDate ) from #sampledata ) c2
on c1.RowN = c2.RowN+1
A little modification to #Kannan's Answer.
Select StartDate = Coalesce (Case when c1.Startdate <= c2.Enddate
then c2.Enddate
Else c1.Startdate
End,
c1.StartDate)
,c1.Enddate, c1.Unit, C1.Id
from
(Select *, RowN = Row_Number() over(partition by Id order by EndDate )
from #sample ) c1
left join
(Select *, RowN = Row_Number() over(partition by Id order by EndDate )
from #sample ) c2
on c1.RowN = c2.RowN+1
I have following Data in myRecords Table
Id Date Name Cash
1 11/25/2016 4:23.123 Ramesh 10000
2 11/25/2016 4:23.173 Suresh 15000
1 11/27/2016 5:23.320 Ramesh 30000
2 11/27/2016 5:23.670 Suresh 40000
and I want to create view So I can get data in following Format
Id1 Date1 Name1 Cash1 Id2 Date2 Name2 Cash2
1 11/25/2016 4:23.123 Ramesh 10000 2 11/25/2016 4:23.173 Suresh 15000
1 11/27/2016 5:23.320 Ramesh 30000 2 11/27/2016 5:23.670 Suresh 40000
How can I do it.
If you are doing date and there will always only be 2 records per day you could convert to drop off the time and do a self join:
DECLARE #myRecords AS TABLE (Id INT, DATE DATETIME, Name VARCHAR(20), CASH INT)
INSERT INTO #myRecords VALUES (1,'11/25/2016 4:23','Ramesh',10000),(2,'11/25/2016 4:23','Suresh',15000)
,(1,'11/27/2016 5:23','Ramesh',30000),(2,'11/27/2016 4:23','Suresh',40000)
SELECT
m1.Id as Id1
,m1.Date as Date1
,m1.Name as Name1
,m1.Cash as Cash1
,m2.Id as Id2
,m2.Date as Date2
,m2.Name as Name2
,m2.Cash as Cash2
FROM
#myRecords m1
LEFT JOIN #myRecords m2
ON CAST(m1.DATE AS DATE) = CAST(m2.DATE AS DATE)
AND m1.Id <> m2.Id
WHERE
m1.Id = 1
Then you can also introduce ROW_NUMBER() to figure out whatever order you want then take all of the ODD RowNumbers and SELF JOIN to the Even RowNumbers:
;WITH cte AS (
SELECT
*
,RowNum = ROW_NUMBER() OVER (ORDER BY Date)
FROM
#myRecords
)
SELECT *
FROM
cte c1
LEFT JOIN cte c2
ON c1.RowNum + 1 = c2.RowNum
WHERE
c1.RowNum % 2 <> 0
As long as your Id joining logic is unclear, this will help In this case but you will need to add Id Filter or additional Identity column and row_number() in future I guess.
SELECT
T.*, TT.*
FROM
[Table] AS T
INNER JOIN
[Table] AS TT
ON T.Date = TT.Date
You can use Cross Apply for the required result set.
SELECT [ID],
[DATE],
[NAME],
[CASH],
B.*
FROM #TABLE1 A
CROSS APPLY (SELECT ID AS ID2,
[DATE] AS DATE2,
[NAME] AS NAME2,
[CASH] AS CASH2
FROM #TABLE1 B
WHERE A.ID < B.ID
AND CONVERT(DATE, A.DATE) = CONVERT(DATE, B.DATE))B
This will also return the same result:
select a.id, a.date, a.name, a.cash, b.id as id2, b.date as date2,
b.name as name2, b.cash as cash2
from myTable a
inner join myTable b on a.id+1 = b.id
and cast(a.date as date) <> cast(b.date as date)
I have rarely use SQL, however for this task it may be the most suitable. I am looking to create a query that is able to detect the first occurrence of an incident for each subject.
Record:
------------------------------
personID | date | incident
------------------------------
1 20150901 F1
2 20150101 B2
3 20150301 C3
1 20150901 B2
3 20150401 R5
2 20150401 C3
1 20150701 F1
Wanted Result:
------------------------------
personID | date | incident
------------------------------
2 20150101 B2
3 20150301 C3
3 20150401 R5
2 20150401 C3
1 20150701 F1
1 20150901 B2
Simply: I am looking for the first (based on date) time the incident occurs for each personID, ignoring if the incident reoccurs.
Thanks
PS. Using SQL Server 2008
Using MIN should work for this:
select personId,incident,MIN(convert(date,date)) as date
from [table]
group by personId,incident
Try this:
;WITH
temp AS (
SELECT personID, date, incident,
rn = ROW_NUMBER() OVER (PARTITION BY personID, incident ORDER BY date)
FROM my_table
)
SELECT *
FROM temp
WHERE rn = 1
You can use row_number function to get the desired result.
Fiddle with sample data
select personid, date, incident
from
(
select *, row_number() over(partition by personid, incident order by date) as rn
from tablename
) x
where x.rn = 1;
I need to do a join but I'm not sure which type. I have a table like this:
Date Amount | FOO
------------------
2012-01-12 x
2012-03-14 y
2012-05-06 z
2012-05-14 aa
2012-09-02 bb
I am joining this with DateDim (Google here: DATE DIM, which is a table of dates (historical and future).
I need a query that would display data like this:
datedim.Date foo.Amount | FOO x DATEDIM
------------------------------------------
2012-01-12 x
2012-01-13 x
2012-01-14 x
... etc...
2012-03-14 y
2012-03-15 y
2012-03-16 y
2012-03-17 y
... etc...
2012-05-06 z
... etc...
Basically, I need the values to persist (were it a left join, it would be NULLs) until the next non-null value. That will persist too... etc..
What I have so far...
SELECT datedim.Date
,CASE
WHEN Amount IS NULL
THEN (SELECT TOP 1 Amount
FROM FOO WHERE foo.Date <= datedim.Date
ORDER BY Date DESC)
ELSE Amount END AS Amount
FROM DATEDIM datedim
LEFT JOIN FOO foo
ON foo.Date = datedim.Date
I need to create a view out of this. I'm getting an error saying ORDER BY is invalid for views, unless specified by TOP??? I do have a TOP in the subquery...
In SQLServer2005+ use recursive CTE
;WITH cte (id, [Date], Amount) AS
(
SELECT ROW_NUMBER() OVER (ORDER BY [Date] ASC) AS id,
[Date], Amount
FROM dbo.your_table t1
), cte2 (id, [Date], [LevelDate], Amount) AS
(
SELECT c1.id, c1.[Date], DATEDIFF(day, c1.[Date], c2.[Date]) AS [LevelDate], c1.Amount
FROM cte c1 LEFT JOIN cte c2 ON c1.id = c2.id - 1
), cte3 (id, [Date], Amount, [Level]) AS
(
SELECT id, [Date], Amount, 1 AS [Level]
FROM cte2 c
UNION ALL
SELECT c.id, DATEADD(day, 1, ct.[Date]) AS [Date], c.Amount, ct.[Level] + 1
FROM cte2 c JOIN cte3 ct ON c.id = ct.id
WHERE c.[LevelDate] > ct.[Level]
)
SELECT [Date], Amount
FROM cte3
ORDER BY Date
OPTION (maxrecursion 0)
Demo on SQLFiddle
I'm sure there are more efficient ways using a CTE, or window functions, but something along these lines should work:
Select
d.Date,
d.FooDate,
f.Amount
From
Foo f
Inner Join (
Select
d.[Date],
Max(f.[Date]) as FooDate
From
Foo f
Inner Join
DateDim d
On f.[Date] < d.[Date]
Group By
d.[Date]
) d
On d.[FooDate] = f.[Date]
http://sqlfiddle.com/#!3/3c7d5/10