SQL - Create a distinct list based on datetime - sql

I'm trying to retrieve a list of results where there are multiple rows which have a duplicate field in different rows but only want to retrieve the row which has been created most recently
Data
loc | created | dest | w | l | h
--------------------------------------------------------------------
2 | 2020/11/09 07:00:00 | north | 12 | 10 | 34
3 | 2020/11/09 07:10:00 | south | 34 | 67 | 23
3 | 2020/11/09 08:13:00 | west | 67 | 22 | 12
I have tried the the following which does give me the rows I require but is missing the extra columns which I require.
Select loc, MAX(created)
from Data
Group By loc
Results Required
loc | created | dest | w | l | h
--------------------------------------------------------------------
2 | 2020/11/09 07:00:00 | north | 12 | 10 | 34
3 | 2020/11/09 08:13:00 | west | 67 | 22 | 12

Try this:
select *
from (
select *, row_number() over (partition by loc order by created desc) rn
from Data
) t
where rn=1

with max_vals as (
Select loc, MAX(created) as max_created
from Data
Group By loc
)
select d.*
from Data d join max_vals m
on d.loc = m.loc and d.created = m.max_created

Related

eSQL multiple join but with conditions

I've 3 tables as under
MERCHANDISE
+-----------+-----------+---------------+
| MERCH_NUM | MERCH_DIV | MERCH_SUB_DIV |
+-----------+-----------+---------------+
| 1 | car | awd |
| 1 | car | awd |
| 2 | bike | 1kcc |
| 3 | cycle | hybrid |
| 3 | cycle | city |
| 4 | moped | fixie |
+-----------+-----------+---------------+
PRIORITY
+----------+-----------+---------+---------+------------+------------+---------------+
| CUST_NUM | SALES_NUM | DOC_NUM | BALANCE | PRIORITY_1 | PRIORITY_2 | PRIORITY_CODE |
+----------+-----------+---------+---------+------------+------------+---------------+
| 90 | 1000 | 10 | 23 | 1 | 6 | NO |
| 91 | 1001 | 20 | 32 | 3 | 7 | PRI |
| 92 | 1002 | 30 | 11 | 2 | 8 | LATE |
| 93 | 1003 | 40 | 22 | 5 | 9 | 1MON |
+----------+-----------+---------+---------+------------+------------+---------------+
ORDER
+----------+-----------+---------+---------+-----------+-----------+
| CUST_NUM | SALES_NUM | DOC_NUM | COUNTRY | MERCH_NUM | MERCH_DIV |
+----------+-----------+---------+---------+-----------+-----------+
| 90 | 1000 | 10 | INDIA | 1 | car |
| 91 | 1001 | 20 | CHINA | 2 | bike |
| 92 | 1002 | 30 | USA | 3 | cycle |
| 93 | 1003 | 40 | UK | 4 | moped |
+----------+-----------+---------+---------+-----------+-----------+
I want to join the left joined table from the last two tables with the first one such that the MERCH_SUB_DIV 'awd' appears only once for each unique combination of merch_num and merch_div
the code I came up with is as under, but I'm not sure how do I eliminate the duplicate row just for the awd
select
ROW#, MERCH.MERCH_NUMBER, ORDPRI.MERCH_NUMBER, ORDPRI.CUST_NUM,
BALANCE, SALES_NUM, ITEM_NUM, RANK, PRIORITY_1
from (
select
ROW_NUMBER() OVER(
PARTITION BY ORD.DOC_NUM, ORD.ITEM_NUM
ORDER BY ORD.DOC_NUM, ORD.ITEM_NUM ASC
) AS Row#,
ORD.CUST_NUM, PRI.CUST_NUM, ORD.MERCH_NUM, ORD.MERCH_DIV, PRI.BALANCE,
pri.DOC_NUM, pri.SALES_NUM, pri.PRIORITY_1, pri.PRIORITY_2
from ORDER as ORD
left join PRIORITY as PRI on ORD.DOC_NUM = PRI.DOC_NUM
and ORD.SALES_NUMBER = PRI.SALES_NUM
where country_name in ('USA', ‘INDIA’)
) as ORDPRI
left join MERCHANDISE as MERCH on ORDPRI.DIV = MERCH.DIV
and ORDPRI.MERCH_NUM = MERCH.MERCH_NUM
You have to use 'DISTINCT' keyword to get unique values, but if your 'Priority table' & 'Order table' contains different values for Same MERCH_NUM then the final result contains the repetation of the 'MERCH_NUM'.
SELECT DISTINCT M.MERCH_NUMBER, O.MERCH_NUMBER, O.CUST_NUM, BALANCE, SALES_NUM,ITEM_NUM,RANK,PRIORITY_1
FROM priority_table P
LEFT JOIN order_table O ON P.CUST_NUM = O.CUST_NUM AND P.SALES_NUM=O.SALES_NUM AND P.DOC_NUM = O.DOC_NUM
LEFT JOIN merchandise_table M ON M.MERCH_NUM = O.MERCH_NUM
A way around can be to add one new Row_Number() in the outermost query having Partition by MERCH_SUB_DIV + all the columns in the final list and then filter final results based on the New Row_Number() . Follows a pseudo code that might help:
select
-- All expected columns in final result except the newRow#
ROW#, MERCH_NUM, CUST_NUM,
BALANCE, SALES_NUM, PRIORITY_1
from (
select
ROW#,
-- the new row number includes all column you want to show in final result
row_number() over ( PARTITION BY MERCH.MERCH_SUB_DIV ,
MERCH.MERCH_NUM, ORDPRI.MERCH_NUM, ORDPRI.CUST_NUM,
BALANCE, SALES_NUM, PRIORITY_1
order by (select 1 )) as newRow# ,
MERCH.MERCH_NUM, ORDPRI.CUST_NUM,
BALANCE, SALES_NUM, PRIORITY_1
from (
-- main query goes here
select
ROW_NUMBER() OVER(
PARTITION BY ORD.DOC_NUM --, ORD.ITEM_NUM
ORDER BY ORD.DOC_NUM ASC --, ORD.ITEM_NUM
) AS Row#,
ORD.CUST_NUM, ORD.MERCH_NUM, ORD.MERCH_DIV as DIV, PRI.BALANCE,
pri.DOC_NUM, pri.SALES_NUM, pri.PRIORITY_1, pri.PRIORITY_2
from #ORDER as ORD
left join #PRIORITY as PRI on ORD.DOC_NUM = PRI.DOC_NUM
and ORD.SALES_NUMBER = PRI.SALES_NUM
where country_name in ('USA', 'INDIA')
) as ORDPRI
left join #MERCHANDISE as MERCH on ORDPRI.DIV = MERCH.DIV
and ORDPRI.MERCH_NUM = MERCH.MERCH_NUM
) as T
-- final filter to get distinct values
where newRow# = 1
Sample code here .. Hope this helps!!

SQL server 2008: join 3 tables and select last entered record from child table against each parent record

I have following 3 tables and last entered reasoncode from Reasons table against each claimno in claims table.
Reasons:
Rid |chargeid| enterydate user reasoncode
-----|--------|-------------|--------|----------
1 | 210 | 04/03/2018 | john | 99
2 | 212 | 05/03/2018 | juliet | 24
5 | 212 | 26/12/2018 | umar | 55
3 | 212 | 07/03/2018 | borat | 30
4 | 211 | 03/03/2018 | Juliet | 20
6 | 213 | 03/03/2018 | borat | 50
7 | 213 | 24/12/2018 | umer | 60
8 | 214 | 01/01/2019 | john | 70
Charges:
chargeid |claim# | amount
---------|-------|---------
210 | 1 | 10
211 | 1 | 24.2
212 | 2 | 5.45
213 | 2 | 76.30
214 | 1 | 2.10
Claims:
claimno | Code | Code
--------|-------|------
1 | AH22 | AH22
2 | BB32 | BB32
Expected result would be like this:
claimno | enterydate | user | reasoncode
--------|-------------|--------|-----------
1 | 01/01/2019 | john | 70
2 | 26/12/2018 | umer | 55
I have applied many solutions but no luck. Following is the latest solution I was trying using SQL Server 2008 but still got incorrect result.
With x As
(
select r.chargeid,r.enterydate,ch.claimno from charges ch
join (select chargeid,max(enterydate) enterydate,user from Reasons group by chargeid) r on r.chargeid = ch.chargeid
)
select x.*,r1.user, r1.reasoncode from x
left outer join Reasons r1 on r1.chargeid = x.chargeid and r1.enterydate = x.enterydate
--group by x.claimno
Is this what you want?
select claimno, enterydate, user, reasoncode
from (select c.claimno, r.*,
row_number() over (partition by c.claimno order by r.entrydate desc) as seqnum
from charges c join
reasons r
on c.chargeid = r.chargeid
) cr
where seqnum = 1;
You can try using row_number()
select * from
(
select r.chargeid,r.enterydate,ch.claimno,user,reasoncode,
row_number() over(partition by ch.claimno order by r1.enterydate desc) as rn
from charges ch left outer join Reasons r1 on r1.chargeid = ch.chargeid
)A where rn=1

Split the date of same column in multiple rows till the next date value is specified - SQL Server

I have this table
+------+------------+-----+
| Code | date | qty |
+------+------------+-----+
| 1 | 06-07-2017 | 44 |
| 1 | 08-07-2017 | 45 |
| 2 | 07-07-2017 | 32 |
| 2 | 09-07-2017 | 33 |
+------+------------+-----+
and I want to display it this way
+------+------------+-----+
| Code | date | qty |
+------+------------+-----+
| 1 | 06-07-2017 | 44 |
| 1 | 07-07-2017 | 44 |
| 1 | 08-07-2017 | 45 |
| 2 | 07-07-2017 | 32 |
| 2 | 08-07-2017 | 32 |
| 2 | 09-07-2017 | 33 |
+------+------------+-----+
I want to split the date of same 'Code' and keep the same value for 'qty' till the next date of same 'Code'.
You need a calendar table and Outer Apply
;WITH cte
AS (SELECT Min([date]) AS st,
Max([date]) ed,
code
FROM Yourtable
GROUP BY code
UNION ALL
SELECT Dateadd(dd, 1, st) AS st,
ed,
code
FROM cte
WHERE Dateadd(dd, 1, st) <= ed)
SELECT c.code,
[date]=c.st,
qty
FROM cte c
OUTER apply (SELECT TOP 1 qty
FROM Yourtable a
WHERE a.code = c.code
AND c.st >= a.[date]
ORDER BY [date] DESC) oa
ORDER BY c.code,st
Note : For the sake of completeness I have used Recursive CTE to generate the dates you can always create a physical calendar table in your database and use it.
Live Demo

Find the first key by date field using sql and output also have other fields

I want to query the first occurrence of every name according to the earliest date. The output should have the complete row. Please help me to write the query in sql.
Input:
Name | ID | payment_date | Pack
------+-------+-----------------+-------
A | 11 | 31-Jan | P
C | 13 | 31-Jan | Q
B | 2 | 31-Jan | R
C | 3 | 28-Jan | P
D | 23 | 29-Jan | Q
B | 11 | 30-Jan | R
A | 17 | 25-Jan | P
C | 13 | 26-Jan | Q
D | 17 | 2-Feb | R
B | 23 | 3-Feb | P
A | 45 | 4-Feb | Q
B | 3 | 5-Feb | R
Output:
Name | ID | payment_date | Pack
-----+-------+--------------+-----
A | 17 | 25-Jan | P
B | 11 | 30-Jan | R
C | 13 | 26-Jan | Q
D | 23 | 29-Jan | Q
You can use the min function, also assuming payment_date is a date type:
select Name, ID, min(payment_date), Pack from mytable
group by payment_date,Name, ID, Pack
order by Name
The downfall about this method is putting all of the fields in the group by.
If your payment_date is a date data type, you can use not exists() like so:
select *
from t
where not exists (
select 1
from t i
where i.Name = t.Name
and i.payment_date < t.payment_date
)
rextester demo (sql server): http://rextester.com/OKB46268
returns
+------+----+-------------+------+
| Name | Id | PaymentDate | Pack |
+------+----+-------------+------+
| A | 17 | 2017-01-25 | P |
| B | 11 | 2017-01-30 | R |
| C | 13 | 2017-01-26 | Q |
| D | 23 | 2017-01-29 | Q |
+------+----+-------------+------+
You can also use Vertica's enhanced LIMIT clause:
WITH
-- input, don't use in real query
input(Name,ID,payment_date,Pack) AS (
SELECT 'A',11,DATE '31-Jan-2017','P'
UNION ALL SELECT 'C',13,DATE '31-Jan-2017','Q'
UNION ALL SELECT 'B',2, DATE '31-Jan-2017','R'
UNION ALL SELECT 'C',3, DATE '28-Jan-2017','P'
UNION ALL SELECT 'D',23,DATE '29-Jan-2017','Q'
UNION ALL SELECT 'B',11,DATE '30-Jan-2017','R'
UNION ALL SELECT 'A',17,DATE '25-Jan-2017','P'
UNION ALL SELECT 'C',13,DATE '26-Jan-2017','Q'
UNION ALL SELECT 'D',17,DATE '2-Feb-2017','R'
UNION ALL SELECT 'B',23,DATE '3-Feb-2017','P'
UNION ALL SELECT 'A',45,DATE '4-Feb-2017','Q'
UNION ALL SELECT 'B',3, DATE '5-Feb-2017','R'
)
-- end of input , start real query here:
SELECT * FROM input
LIMIT 1 OVER(PARTITION BY Name ORDER BY payment_date)
;
Happy playing ...
Marco the Sane

SQL order by highest to lowest in one table referencing another table in an UPDATE

Hey all I have the following tables that need in order to get data from one that matches the other and have it from highest to lowest depending on the int of TempVersion.
UPDATE
net_Users
SET
net_Users.DefaultId = b.TId
FROM
(SELECT
TOP 1 IndivId,
TId
FROM
UTeams
WHERE
UTeams.[Active] = 1
ORDER BY
TempVersion DESC
) AS b
WHERE
net_Users.IndivId = b.IndivId
In the above I am trying to order from the highest TempVersion to the lowest.
The query above seems to just update 1 of those records with the TempVersion and stop there. I am needing it to loop to find all associated users with the same IndivId matching.
Anyone able to help me out with this?
sample data
net_Users:
name | DefaultId | IndivId | etc...
--------+-----------+---------+-------
Bob | | 87 | etc...
Jan | | 231 | etc...
Luke | | 8 | etc...
UTeams:
IndivId | TempVersion | etc...
--------+-------------+-------
8 | 44 | etc...
17 | 18 | etc...
8 | 51 | etc...
8 | 2 | etc...
7 | 22 | etc...
8 | 125 | etc...
87 | 10 | etc...
14 | 88 | etc...
8 | 5 | etc...
15 | 54 | etc...
65 | 11 | etc...
87 | 15 | etc...
39 | 104 | etc...
And the output I would be needing is (going to choose IndivId 8):
In net_users:
Name | DefaultId | IndivId | etc...
-----+-----------+---------+-------
Luke | 125 | 8 | etc...
Luke | 51 | 8 | etc...
Luke | 44 | 8 | etc...
Luke | 5 | 8 | etc...
Luke | 2 | 8 | etc...
I think this is what you were trying to do:
update net_Users
set net_Users.DefaultId = coalesce((
select top 1 TId
from UTeams
where UTeams.[Active] = 1
and net_Users.IndivId = UTeams.IndivId
order by u.TempVersion desc
)
,net_Users.DefaultId
)
another way using cross apply()
update n
set DefaultId = coalesce(x.Tid,n.DefaultId)
from net_Users as n
cross apply (
select top 1 TId
from UTeams as u
where u.[Active] = 1
and n.IndivId = u.IndivId
order by u.TempVersion desc
) as x
another way to do that with a common table expression and row_number()
with cte as (
select
n.IndivId
, n.DefaultId
, u.Tid
, rn = row_number() over (
partition by n.IndivId
order by TempVersion desc
)
from net_users as n
inner join UTeams as u
on n.IndivId = u.IndivId
where u.[Active]=1
)
update cte
set DefaultId = Tid
where rn = 1