Just a simple question of SQL that I was not able to figure out the solution.
table 2 AUditLog
Machine SettingCode User changeSTR timeChanged Order
A C1 U1 0->10 12/5/2020 10h00 1
A C1 U2 10->3 12/5/2020 10h07 1
A C1 U1 0->3 12/5/2020 11h00 3
I want to do a select of this table AuditLog and have. (in the cases of the same machine, settingCode, Order) I want to have a result with the users of the most recente change.
Machine SettingCode LastUserChange Order
A C1 U2 1
A C1 U1 3
A simple and portable solution is to filter with a correlated subquery:
select a.*
from auditLog a
where a.timeChanged = (
select max(a1.timeChanged)
from auditLog a1
where
a1.machine = a.machine
and a1.settingCode = a.settingCode
and a1.order = a.order
)
You can also use row_number(), if your database, which you did not tell, supports window functions:
select *
from (
select
a.*,
row_number() over(
partition by machine, settingCode, a.order
order by timeChanged desc) rn
from auditLog a
) a
where rn = 1
Note that order is a SQL keyword, hence not a good choice for a column name.
Related
I need to join to the same table repeatedly but this looks ugly. Any suggestions appreciated. Below is simplified SQL, I have 8 tables in the subquery and it produces many duplicate records of the same date, so I need to find only the newest record for each client. (I don't think DB and/or version should matter, but I am using DB2 11.1 LUW)
select c.client_num, a.eff_date, t.trx_date
from client c
join address a on(a.id = c.addr_id)
join transaction t on(t.addr_id = a.id)
{many other joins}
where {many conditions};
select SQ.*
from [ABOVE_SUBQUERY] SQ
join
(select client_num, max(eff_date) AS newest_date from [ABOVE_SUBQUERY] group by client_num) AA
ON(SQ.client_num = AA.client_num and SQ.eff_date = AA.newest_date)
join
(select client_num, max(trx_date) AS newest_date from [ABOVE_SUBQUERY] group by client_num) TT
ON(SQ.client_num = TT.client_num and SQ.trx_date = TT.newest_date)
I need to fine only the newest record for each client.
Can't you just use row_number()?
select t.*
from (select t.*,
row_number() over (partition by client_num order by eff_date desc, eff_time desc) as seqnum
from <whatever> t
) t
where seqnum = 1;
I'm working with the following code to only get one associated person per case, using the MAX Associated Type to get the top 1.
Associated Type is not a GUID, rather looks like:
Responsible Party, Primary Physician, etc.
It just so happens that Responsible Party is the last alphabetical option, so it's a lucky workaround. Not every case has a responsible party, however, and if there isn't a responsible party, the next top associated person is 'good enough' and will be highlighted as a data error anyway.
The result shows every single associated person (rather than top 1), but shows all of them as Responsible Party, which is not true. What am I doing wrong here?
FROM T_LatestIFSP Ltst
LEFT OUTER JOIN (
SELECT
Clas.ClientCase_ID,
MAX(Astp.AssociatedType) AS AssociatedType
FROM
T_ClientAssociatedPerson Clas
Inner Join T_AssociatedType Astp
ON Clas.AssociatedType_ID = Astp.AssociatedType_ID
GROUP BY Clas.ClientCase_ID
) AS Astp ON Ltst.ClientCase_ID = Astp.ClientCase_ID
LEFT OUTER JOIN T_ClientAssociatedPerson Clas
on Clas.ClientCase_ID = Astp.ClientCase_ID
LEFT OUTER JOIN T_AssociatedPerson Aspr
ON Aspr.AssociatedPerson_ID = Clas.AssociatedPerson_ID
To get AssocId in the select, you have to do a self join.
LEFT OUTER JOIN
(your subselect with max(AssociatedType) in it) AS Astp
INNER JOIN T_AssociatedType AS Astp2
ON (whatever the primary key is on that table)
Then you can add astp2.AssociationTypeId to the original SELECT.
You can try this query.
Make rn from your order condition in CASE WHEN
You can use Rank with window function to make rank number in subquery, then get rnk=1 data row.
;WITH CTE AS (
SELECT ClientCase_ID,
AssociatedPerson_ID,
AssociatedPersonType,
AssociatedType_ID,
RANK() OVER(PARTITION BY ClientCase_ID ORDER BY rn desc,AssociatedPerson_ID) rnk
FROM (
SELECT t1.ClientCase_ID,
t1.AssociatedPerson_ID,
t1.AssociatedPersonType,
t1.AssociatedType_ID,
(CASE
WHEN t1.AssociatedPersonType = 'ResPonsible Party' then 16
WHEN t1.AssociatedPersonType = 'Primary Physician' then 15
ELSE 14
END) rn
FROM T t1
INNER JOIN T t2 ON t1.ClientCase_ID = t2.AssociatedPerson_ID
UNION ALL
SELECT t2.AssociatedPerson_ID,
t1.AssociatedPerson_ID,
t1.AssociatedPersonType,
t2.AssociatedType_ID,
(CASE
WHEN t2.AssociatedPersonType = 'ResPonsible Party' then 16
WHEN t2.AssociatedPersonType = 'Primary Physician' then 15
ELSE 14
END) rn
FROM T t1
INNER JOIN T t2 ON t1.ClientCase_ID = t2.AssociatedPerson_ID
) t1
)
select DISTINCT ClientCase_ID,AssociatedPerson_ID,AssociatedPersonType,AssociatedType_ID
FROM CTE
WHERE rnk = 1
sqlfiddle
Also, you can try to use CROSS APPLY with value instead of UNION ALL
;with CTE AS (
SELECT v.*, (CASE
WHEN v.AssociatedPersonType = 'ResPonsible Party' then 16
WHEN v.AssociatedPersonType = 'Primary Physician' then 15
ELSE 14
END) rn
FROM T t1
INNER JOIN T t2 ON t1.ClientCase_ID = t2.AssociatedPerson_ID
CROSS APPLY (VALUES
(t1.ClientCase_ID,t1.AssociatedPerson_ID,t1.AssociatedPersonType, t1.AssociatedType_ID),
(t2.AssociatedPerson_ID,t1.AssociatedPerson_ID,t2.AssociatedPersonType, t2.AssociatedType_ID)
) v (ClientCase_ID,AssociatedPerson_ID,AssociatedPersonType,AssociatedType_ID)
)
SELECT distinct ClientCase_ID,AssociatedPerson_ID,AssociatedPersonType,AssociatedType_ID
FROM
(
SELECT *,
RANK() OVER(PARTITION BY ClientCase_ID ORDER BY rn desc,AssociatedPerson_ID) rnk
FROM CTE
) t1
WHERE rnk = 1
sqlfiddle
Note
you can add your customer order number in CASE WHEN
[Results]:
| ClientCase_ID | AssociatedPerson_ID | AssociatedPersonType | AssociatedType_ID |
|---------------|---------------------|----------------------|-------------------|
| 01 | 01 | ResPonsible Party | 16 |
| 02 | 03 | Physician Therapist | 24 |
I solved the problem with the following code:
LEFT OUTER JOIN T_ClientAssociatedPerson Clas
on Clas.ClientCase_ID = Ltst.ClientCase_ID
and
CASE
WHEN Clas.AssociatedType_ID = 16 AND Clas.ClientCase_ID = Ltst.ClientCase_ID THEN 1
WHEN Clas.AssociatedType_ID <> 16 AND Clas.AssociatedType_ID = (
SELECT TOP 1 Clas.AssociatedType_ID
FROM T_ClientAssociatedPerson Clas
WHERE Clas.ClientCase_ID = Ltst.ClientCase_ID
ORDER BY AssociatedType_ID DESC
) THEN 1
ELSE 0
END = 1
How to limit my select statement to only show one ?
If you are using Oracle 12c, you can use CROSS APPLY instead of INNER JOIN.
CROSS APPLY (SELECT inactivationremark,
createts
FROM t_se_internalrating ir
WHERE ir.RATINGSTATUS = 'Deactivated'
AND ir.PARTNERID = p1.ID
ORDER BY ir.createts DESC
fetch first 1 rows only
) ir
Look for CROSS APPLY or OUTER APPLY - this is the pattern you are looking for. See here.
If you are using a lower version, you can use the ROW_NUMBER function:
inner join
( SELECT
inactivationremark,
createts,
row_number() OVER(
PARTITION BY ir.partnerid ORDER BY ir.createts DESC) rn
FROM t_se_internalrating ir
WHERE ir.ratingstatus = 'Deactivated')
) ir
ON ir.partnerid = p1.id AND ir.rn < 2
The AND rn < 2 condition ensures that only the latest ratings are included.
I have the following query that I am working on. The goal is to insert the [AppID] and randomly selected [ufid] that meet the criteria in the where clause without inserting duplicates. I have researched the TABLESAMPLE and Random() but was unable to figure this out.
For example: #mult_nuf table has 4 records with the AppID = 123456 and Major = 'GEBOX'. The #temp_rUF will have a record in the table with the ufid = 'UF7' and sh_plan = 'GEBOX'.I need to insert the [App_ID] and the [ufid] of another [sh_plan] into a temp table WHERE the [Major] and [sh_plan] are NOT be the same. So far a record for every [ufid] is being inserted with the same [Appid]. I have 45 [ufid} in the table so the temp table has 45 records for the same [AppID]. Should only be 4 records for the [AppID] with 4 random [ufid]..
mult_nuf table
AppID Major
004540036 GEBOX
004540036 GEBOX
004540036 GEBOX
004540036 GEBOX
The #temp_ruf table
ufID sh_Plan
U1 GECCE
U2 REDSG
U5 GFRTY
U7 GEBOX
U8 JKIUTY
Sample Output should look like
App_ID ufID
004540036 U1
004540036 U2
004540036 U5
004540036 U8
Query I am working with
WITH Match_NomineesWithReviewers AS
(
SELECT DISTINCT
[AppID],
RTRIM(Major) AS Major
FROM
#mult_nuf
)
SELECT
m.[AppID],
r.ufid
INTO
#TempNTable
FROM
Match_NWithR m
CROSS APPLY
(SELECT ir.ufid
FROM #temp_rUF ir
WHERE m.Major <> ir.sh_plan) r
Assuming you want to do this on a set of AppID's, I'd use ROW_NUMBER and ORDER BY newid() for random, then limit to the first 4 results, something like this:
WITH Match_NomineesWithReviewers AS
(
SELECT
[AppID],
RTRIM(Major) AS Major
FROM
#mult_nuf
GROUP BY
[AppID],
RTRIM(Major)
)
, rownum_matches AS (
SELECT
m.[AppID],
r.ufid,
ROW_NUMBER() OVER (PARTITION BY m.[AppID] ORDER BY newid()) AS rownum
FROM
Match_NomineesWithReviewers m
JOIN
#temp_rUF t ON t.sh_Plan != m.Major
)
SELECT [AppID], ufid FROM rownum_matches WHERE rownum <= 4
If you need it to match the original number of records, maybe something like this:
WITH Match_NomineesWithReviewers AS
(
SELECT
[AppID],
RTRIM(Major) AS Major,
COUNT(1) AS rowcnt
FROM
#mult_nuf
GROUP BY
[AppID],
RTRIM(Major)
)
, rownum_matches AS (
SELECT
m.[AppID],
r.ufid,
m.rowcnt,
ROW_NUMBER() OVER (PARTITION BY m.[AppID] ORDER BY newid()) AS rownum
FROM
Match_NomineesWithReviewers m
JOIN
#temp_rUF t ON t.sh_Plan != m.Major
)
SELECT [AppID], ufid FROM rownum_matches rm WHERE rownum <= rowcnt
You can try something like this. It should work if the appid's are all the same.
INSERT INTO ATempTable
SELECT TOP (SELECT COUNT(1) FROM mult_nuf) Appid,
ufID
FROM
(SELECT DISTINCT *
FROM mult_nuf
CROSS JOIN temp_ruf
WHERE major <> sh_plan) BaseQuery
ORDER BY NEWID()
My table looks like this (Totally different names)
ID Column1--Column2---Column3--------------Column30
X 0 2 6 0101 31
I want to find the second maximum value of Column1 to Column30 and Put the column_Name in a seperate column.
First row would look like :
ID Column1--Column2---Column3--------------Column30------SecondMax
X 0 2 6 0101 31 Column3
Query :
Update Table
Set SecondMax= (select Column_Name from table where ...)
with unpvt as (
select id, c, m
from T
unpivot (c for m in (c1, c2, c3, ..., c30)) as u /* <-- your list of columns */
)
update T
set SecondMax = (
select top 1 m
from unpvt as u1
where
u1.id = T.id
and u1.c < (
select max(c) from unpvt as u2 where u2.id = u1.id
)
order by c desc, m
)
I really don't like relying on top but this isn't a standard sql question anyway. And it doesn't do anything about ties other than returning the first column name by order of alphabetical sort.
You could use a modification via the condition below to get the "third maximum". (Obviously the constant 2 comes from 3 - 1.) Your version of SQL Server lets you use a variable there as well. I think SQL 2012 also supports the limit syntax if that's preferable to top. And since it should work for top 0 and top 1 as well, you might just be able to run this query in a loop to populate all of your "maximums" from first to thirty.
Once you start having ties you'll eventually get a "thirtieth maximum" that's null. Make sure you cover those cases though.
and u1.c < all (
select top 2 distinct c from unpvt as u2 where u2.id = u1.id
)
And after I think about it. If you're going to rank and update so many columns it would probably make even more sense to use a proper ranking function and do the update all at once. You'll also handle the ties a lot better even if the alphabetic sorting is still arbitrary.
with unpvt as (
select id, c, m, row_number() over (partition by id order by c desc, m) as nthmax
from T
unpivot (c for m in (c1, c2, c3, ..., c30)) as u /* <-- your list of columns */
)
update T set
FirstMax = (select c from unpvt as u where u.id = T.id and nth_max = 1),
SecondMax = (select c from unpvt as u where u.id = T.id and nth_max = 2),
...
NthMax = (select c from unpvt as u where u.id = T.id and nth_max = N)