Specific group by latest date in SQL Server - sql

I want to run a SQL query on the following set of data
date creation_date value
------------------------------------
2018-01-01 2017-05-05 1
2018-01-02 2017-05-05 0
2018-01-03 2017-05-05 1
2018-01-04 2017-05-05 0
2018-01-05 2017-05-05 1
2018-01-06 2017-05-05 1
2018-01-02 2017-05-11 5
I want to get the following results
2018-01-01 2017-05-05 1
2018-01-02 2017-05-11 5
2018-01-03 2017-05-05 1
2018-01-04 2017-05-05 0
2018-01-05 2017-05-05 1
2018-01-06 2017-05-05 1
Basically I want to get all the dates, group it by dates and get the latest creation date and get the value for that creation date.
I tried
select date, max(Creation_date), value
from datasource
group by date, blocked
but that doesn't do it.

I think you can use query like this:
select *
from (
select *
, row_number() over (partition by date, blocked order by creation_date desc) seq
from datasource) t
where t.seq = 1;
SQL Server Fiddle Demo

Try to use subquery and join with it
SELECT d.*
FROM datasource d
JOIN
(
SELECT [date],MAX(Creation_date) LastCreationDate
FROM datasource
GROUP BY [date]
) l
ON d.[date]=l.[date] AND d.Creation_date=l.LastCreationDate
Or the second variant if Creation_date is common for all the [date]
SELECT *
FROM datasource
WHERE Creation_date=(SELECT MAX(Creation_date) FROM datasource)

Related

How to filter out multiple downtime events in SQL Server?

There is a query I need to write that will filter out multiples of the same downtime event. These records get created at the exact same time with multiple different timestealrs which I don't need. Also, in the event of multiple timestealers for a downtime event I need to make the timestealer 'NULL' instead.
Example table:
Id
TimeStealer
Start
End
Is_Downtime
Downtime_Event
1
Machine 1
2022-01-01 01:00:00
2022-01-01 01:01:00
1
Malfunction
2
Machine 2
2022-01-01 01:00:00
2022-01-01 01:01:00
1
Malfunction
3
NULL
2022-01-01 00:01:00
2022-01-01 00:59:59
0
Operating
What I need the query to return:
Id
TimeStealer
Start
End
Is_Downtime
Downtime_Event
1
NULL
2022-01-01 01:00:00
2022-01-01 01:01:00
1
Malfunction
2
NULL
2022-01-01 00:01:00
2022-01-01 00:59:59
0
Operating
Seems like this is a top 1 row of each group, but with the added logic of making a column NULL when there are multiple rows. You can achieve that by also using a windowed COUNT, and then a CASE expression in the outer SELECT to only return the value of TimeStealer when there was 1 event:
WITH CTE AS(
SELECT V.Id,
V.TimeStealer,
V.Start,
V.[End],
V.Is_Downtime,
V.Downtime_Event,
ROW_NUMBER() OVER (PARTITION BY V.Start, V.[End], V.Is_Downtime,V.Downtime_Event ORDER BY ID) AS RN,
COUNT(V.ID) OVER (PARTITION BY V.Start, V.[End], V.Is_Downtime,V.Downtime_Event) AS Events
FROM(VALUES('1','Machine 1',CONVERT(datetime2(0),'2022-01-01 01:00:00'),CONVERT(datetime2(0),'2022-01-01 01:01:00'),'1','Malfunction'),
('2','Machine 2',CONVERT(datetime2(0),'2022-01-01 01:00:00'),CONVERT(datetime2(0),'2022-01-01 01:01:00'),'1','Malfunction'),
('3','NULL',CONVERT(datetime2(0),'2022-01-01 00:01:00'),CONVERT(datetime2(0),'2022-01-01 00:59:59'),'0','Operating'))V(Id,TimeStealer,[Start],[End],Is_Downtime,Downtime_Event))
SELECT ROW_NUMBER() OVER (ORDER BY ID) AS ID,
CASE WHEN C.Events = 1 THEN C.TimeStealer END AS TimeStealer,
C.Start,
C.[End],
C.Is_Downtime,
C.Downtime_Event
FROM CTE C
WHERE C.RN = 1;

SQL Select with grouping and replacing a column

I have a requirement in which I need to retrieve rows in a select query in which I have to get value of END_DATE as EFFECTIVE_DATE -1 DAY for the records with same key (CARD_NBR in this case)
I have tried using it by GROUP by but I am not able to get the desired output. Could someone please help in guiding me ? The record with most recent effective date should have END_DATE as 9999-12-31 only.
Table:
CARD_NBR
SERIEL_NO
EFFECTIVE_DATE
END_DATE
12345
1
2021-01-01
9999-12-31
12345
2
2021-01-25
9999-12-31
12345
3
2021-02-15
9999-12-31
67899
1
2021-03-01
9999-12-31
67899
2
2021-04-02
9999-12-31
67899
3
2021-05-24
9999-12-31
Output:
CARD_NBR
SERIEL_NO
EFFECTIVE_DATE
END_DATE
12345
1
2021-01-01
2021-01-24
12345
2
2021-01-25
2021-02-14
12345
3
2021-02-15
9999-12-31
67899
1
2021-03-01
2021-04-01
67899
2
2021-04-02
2021-05-24
67899
3
2021-05-24
9999-12-31
You can use lead():
select t.*,
lead(effective_date - interval '1 day', 1, effective_date) over (partition by card_nbr order by effective_date) as imputed_end_date
from t;
Date manipulations are highly database-dependent so this uses Standard SQL syntax. You can incorporate this into an update, but the best approach also depends on the database.
SQLite v.3.25 now supports windows function and you can use below code to get your result.
SELECT A.CARD_NBR,
A.SRL_NO,
A.START_DT,
COALESCE(B.START_DT,A.END_DT) AS END_DT
FROM
(
SELECT A.CARD_NBR,
A.SRL_NO,
A.START_DT,
A.END_DT,
ROW_NUMBER() OVER(PARTITION BY A.CARD_NBR ORDER BY A.SRL_NO ASC) RNUM1
FROM T1 A
)A
LEFT JOIN
(
SELECT B.CARD_NBR,
B.SRL_NO,
B.START_DT,
B.END_DT,
ROW_NUMBER() OVER(PARTITION BY B.CARD_NBR ORDER BY B.SRL_NO ASC) RNUM1
FROM T1 B
)B
ON A.CARD_NBR=B.CARD_NBR
AND A.RNUM1+1=B.RNUM1

T-SQL max date and min date between two date

First, thanks for your time and your help!
I have two tables:
Table 1
PersId name lastName city
---------------------------------------
1 John Smith Tirana
2 Leri Nice Tirana
3 Adam fortsan Tirana
Table 2
Id PersId salesDate
--------------------------------------------
1 1 2017-01-22 08:00:40 000
2 2 2017-01-22 09:00:00 000
3 1 2017-01-22 10:00:00 000
4 1 2017-01-22 20:00:00 000
5 3 2017-01-15 09:00:00 000
6 1 2017-01-21 09:00:00 000
7 1 2017-01-21 10:00:00 000
8 1 2017-01-21 18:55:00 000
I would like to see the first recent sales between two dates according to each city for each day I want to bring it empty if I do not have a sale
SalesDate > '2017-01-17 09:00:00 000'
and SalesDate < '2017-01-23 09:00:00 000'
Table 2, id = 5 because the record is not in the specified date range
If I wanted my results to look like
Id PersId MinSalesDate MaxSalesDate City
-----------------------------------------------------------------------------
1 1 2017-01-22 08:00:40 000 2017-01-22 20:00:00 000 Tirana
2 2 2017-01-22 09:00:00 000 null Tirana
3 3 null null Tirana
4 1 2017-01-21 09:00:00 000 2017-01-21 18:55:00 000 Tirana
You dont identify how to get ID in the result. You appear to just want Row_Number(). I will leave that out, but this should get you started. You may have to work out conversion issues in the data range check, and I havent checked the query for syntax errors, I will leave that to you.
Select T1.PersId, City
, Min(T2.salesDate) MinSalesDate
, Max(T2.salesDate) MaxSalesDate
From Table1 T1
Left Join Table2 T2
On T1.PersId = T2.PersId
And T2.salesDate Between '2017-01-17 09:00:00 000' And < '2017-01-23 09:00:00 000'
Group BY T1.PersId, T2.City
Try the following using row_number to get min and max sale dates:
SELECT
T2.Id, T1.PersId, T2.MIN_salesDate, T2.MAX_salesDate, T1.City
FROM Table1 T1
LEFT JOIN
(
SELECT MIN(Id) as Id, PersId, MIN(salesDate) as MIN_salesDate, MAX(salesDate) as MAX_salesDate
FROM
(
SELECT
*
,ROW_NUMBER() OVER (PARTITION BY PersId ORDER BY salesDate ASC) as RNKMIN
,ROW_NUMBER() OVER (PARTITION BY PersId ORDER BY salesDate DESC) as RNKMAX
FROM Table2 T2
WHERE salesDate Between '2017-01-17 09:00:00 000' And '2017-01-23 09:00:00 000'
) temp
WHERE RNKMIN = 1 or RNKMAX = 1
GROUP BY PersId
) T2
on T1.PersId = T2.PersId

Select Max() and Min() date and Sum up quantity

I have table with data as below
StartDate EndDate ID Qty
2017-09-01 2017-10-01 PJFC1000205 1
2017-10-01 2017-11-01 PJFC1000205 2
2017-11-01 2017-12-01 PJFC1000205 3
2017-12-01 2018-01-01 PJFC1000205 4
I wish sum up the qty and wish the output as below
StartDate EndDate ID Qty
2017-09-01 2018-01-01 PJFC1000205 10
Is it possible to do so? How I can do it?
I'm using MSSQL 2014.
Please guide me, thanks.
Using the group by on ID and aggregate functions on the other fields should do the trick.
SELECT min(Start_Date), max(End_Date), ID, sum(Qty)
FROM table
GROUP BY ID;

SQL how to select rows with count of 2 timestamp entries and 1 filekey

I need to get filekey and dttmstamps where the count of the dttmstamp+filekey combination = 2
This query:
SELECT [FILEKEY]
,(Dateadd(dd,0,Datediff(dd,0,DTTMSTAMP))) as 'DTTMSTAMP'
yields:
UniqueID Filekey DTTMSTAMP
1 1 2014-07-21 00:00:00.000
2 1 2014-07-21 00:00:00.000
3 1 2014-07-24 00:00:00.000
4 1 2014-07-24 00:00:00.000
5 1 2014-07-24 00:00:00.000
6 1 2014-07-24 00:00:00.000
7 1 2014-07-25 00:00:00.000
8 1 2014-07-25 00:00:00.000
I would like the results to read as follows:
FileKey DTTMSTAMP
1 2014-07-21 00:00:00.000
1 2014-07-25 00:00:00.000
and not return 2014-7-24 due to there not being a count of 2
select FileKey, DTTMSTAMP = (Dateadd(day,0,Datediff(day,0,DTTMSTAMP)))
from t
group by FileKey, (Dateadd(day,0,Datediff(day,0,DTTMSTAMP)))
having count(UniqueID)=2 -- alternately > 1 for all duplicates
have you tried any option yet?
select Filekey,DTTMSTAMP
from <table>
Group by Filekey,DTTMSTAMP
having (count(1)=2)
Given that your table is named FILES, this will result in the set of unique (FILEKEY, DTTMSTAMP) pairs where exactly two are present in the table.
SELECT [FILES].[FILEKEY]
, [DATE_ONLY].[DTTMSTAMP]
FROM [FILES]
CROSS APPLY (
SELECT (Dateadd(dd, 0, Datediff(dd, 0, [FILES].[DTTMSTAMP]))) AS [DTTMSTAMP]
) AS [DATE_ONLY]
GROUP BY [FILES].[FILEKEY]
, [DATE_ONLY].[DTTMSTAMP]
HAVING COUNT([DATE_ONLY].[DTTMSTAMP]) = 2;
The CROSS APPLY is there to allow for easy reference of the date-only part in both GROUP BY, HAVING, and SELECT. Using SqlZim's solution, you will have duplicate transform logic.
The APPLY operators were introduced in SQL Server 2005.