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

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

Related

SQL - Create a distinct list based on datetime

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

Query to show top 3 records per user where the user has submitted a minimum of 3?

I have in a table in MS SQL with multiple entries per user. I am trying to get the top 3 entries by date for each user. I have a query that returns returns the maximum top 3 entries per user but is also returning users which have submitted 2 or 1 entries. I have a join with another table only to get the email address. I would like it to return only the entries by john and dave as they have 3 entries. If they have more than 3 just return the top 3 by submitmonth.
select * from (
select m.Email, q.submitmonth, q.A2, q.A7, q.C7, q.C8, q.C16, q.F9, q.F10, q.G4, q.H1, q.H2, q.J2, q.J13, q.K18, q.N1, q.P6,
row_number() over (partition by q.userid order by q.submitmonth desc) as Submitted
from dbo.submission q
left join dbo.users m
on q.UserId = m.UserId ) ranks
where Submitted < 4
this returns
| Email | submitmonth | A2 | A7 | Submitted
| | | | |
| john#yahoo.com | 01/08/2020 | 2 | 4 | 1
| john#yahoo.com | 01/07/2020 | 8 | 8 | 2
| john#yahoo.com | 01/06/2020 | 2 | 1 | 3
| bob#gmail.com | 01/08/2020 | 1 | 3 | 1
| bob#gmail.com | 01/07/2020 | 9 | 7 | 2
| pete#yahoo.co.uk | 01/08/2020 | 8 | 5 | 1
| dave#gmail.com | 01/06/2020 | 3 | 6 | 1
| dave#gmail.com | 01/04/2020 | 5 | 6 | 2
| dave#gmail.com | 01/02/2020 | 1 | 6 | 3
Thanks for your help.
Add the count window function and then filter on it.
select *
from (
select m.Email, q.submitmonth, q.A2, q.A7, q.C7, q.C8, q.C16, q.F9, q.F10, q.G4, q.H1, q.H2, q.J2, q.J13, q.K18, q.N1, q.P6
, row_number() over (partition by q.userid order by q.submitmonth desc) as Submitted
, count(*) over (partition by q.userid) TotalSubmitted
from dbo.submission q
left join dbo.users m on q.UserId = m.UserId
) ranks
where Submitted < 4 and TotalSubmitted >= 3

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, Update with most recent data info

I have 2 tables shown below:
Table 1
Student ID - DATE_NO - SCORE
Table 2
STUDENT_ID - DATE_NO - HT - WT
Table 1 has the physical test scores and the date of the test for each student while Table 2 lists their height (HT) and weight (WT) and the date they were measured.
Example Data:
Table 1
Student ID | DATE_NO | SCORE |
125 | 3 | 90 |
572 | 6 | 75 |
687 | 11 | 95 |
Table 2
Student_ID | DATE_NO | HT | WT |
125 | 2 | 70 | 150 |
125 | 3 | 72 | 155 |
125 | 6 | 72 | 160 |
572 | 2 | 70 | 200 |
572 | 5 | 70 | 225 |
572 | 8 | 70 | 215 |
572 | 9 | 70 | 220 |
687 | 4 | 65 | 140 |
687 | 7 | 67 | 150 |
687 | 11 | 70 | 155 |
687 | 12 | 67 | 160 |
I am not guaranteed to have the exact same DATE_NO for both HT/WT and the Test score date. I want the most recent HT and WT for each student when they took their physical test. Based on the example data above, the optimal join would give me the table below:
Modified Table 1
Student ID | DATE_NO | HT | WT |
125 | 3 | 72 | 155 |
572 | 6 | 70 | 225 |
687 | 11 | 70 | 155 |
I'd like to use the UPDATE statement on Table 1, so after altering Table 1 with HT int and WT int, I attempt to do the following:
UPDATE T1
SET HT = T2.HT, WT = T2.WT
FROM Table_1 as T1
INNER JOIN Table_2 AS T2 ON T1.STUDENT_ID = T2.STUDENT_ID
WHERE (T1.DATE_NO) >= (T2.DATE_NO)
But the result gives me the FIRST record that meets the criteria. Switching greater than to less than [ >= to <= ] Make the HT/WT for each student the entries for Month 6,8, and 12) when it should be month 3,8, and 11. Any suggestions?
FYI: Won't be able to apply any solutions till Friday.
Is it something like this you're looking for:
UPDATE Q
SET
T1_HT = T2_HT
, T1_WT = T2_WT
FROM
(
SELECT
T1.HT T1_HT
, T1.WT T1_WT
, T2.HT T2_HT
, T2.WT T2_WT
, ROW_NUMBER() OVER (PARTITION BY T1.STUDENT_ID ORDER BY T2.DATE_NO DESC) R
FROM
Table_1 T1
JOIN Table_2 T2 ON
T1.STUDENT_ID = T2.STUDENT_ID
AND T2.DATE_NO <= T1.DATE_NO
) Q
WHERE R = 1
SELECT ts.student_id,
ts.date_no,
hw.ht,
hw.wt
FROM test_scores ts,
ht_wt hw
WHERE hw.student_id = ts.student_id
AND hw.date_no <= ts.date_no
AND hw.date_no =
(SELECT max(date_no)
FROM ht_wt
WHERE date_no <= ts.date_no
AND student_id = ts.student_id)
sql fiddle here

Different results with agregate and analytical with distinct functions

I can't understand why there is the difference in results between two queries:
1) select distinct sum(lot.lot_size) over (partition by lot.detail_id) buying_size, lot.f_detail_id
from buying
join lot on lot.lot_id = buying.lot_id
where exists (select 1
from selling s
join buying b on b.buying_id = s.buying_buying_id
where s.deal_id = 123456
and buying.deal_id = b.deal_id
and s.selling_detailid = buying.buying_detailid)
and buying.buying_status <> 'Canceled'
result:
|buying_size|f_detail_id |
|-----------|------------|
| 105 | 1 |
| 200 | 2 |
| 75 | 3 |
| 225 | 4 |
| 300 | 5 |
2) select distinct *
from (select sum(lot.lot_size) over (partition by lot.detail_id) buying_size, lot.f_detail_id
from buying
join lot on lot.lot_id = buying.lot_id
where exists (select 1
from selling s
join buying b on b.buying_id = s.buying_buying_id
where s.deal_id = 123456
and buying.deal_id = b.deal_id
and s.selling_detailid = buying.buying_detailid)
and buying.buying_status <> 'Canceled')
result:
|buying_size|f_detail_id |
|-----------|------------|
| 105 | 1 |
| 200 | 2 |
| 75 | 3 |
| 225 | 4 |
| 150 | 5 |
I know that this query might be written by another way with using GROUP BY but the main thing I'm interested in is why the result of analytical function depends on DISTINCT.