I have the below query/subquery. I am trying to get the CIty, State, and Zipcode from the record in the AOD table and the First and Last from the Employee Original Date table. Can anyone provide guidance on how to extract the data form the sub query? Thank you!
SELECT eod.FIRST_NAME
,eod.LAST_NAME
,eod.SSN
,aodf.SSN
,aodf.CITY
,aodf.STATE
,aodf.ZipCode
FROM EMPLOYEE_ORIG_DATE eod
JOIN
(SELECT aod.ORIG_DATE
,aod.SSN
,aod.ADDRESS_KEY
,aod.Address_1 as AddressLine1
,aod.Address_2 as AddressLine2
,aod.City
,aod.State
,aod.Zip as ZipCode
,aod.Country as CountryCode
,aod.Telephone as HomeNumber
FROM ADDRESS_ORIG_DATE aod
INNER JOIN
(SELECT SSN, MAX(ORIG_DATE) ORIG_DATE
FROM ADDRESS_ORIG_DATE
GROUP BY SSN) aod2
ON aod.SSN = aod2.SSN
AND aod.ORIG_DATE = aod2.ORIG_DATE) aodf
ON eod.SSN = aodf.SSN
AND eod.ADRESS_KEY = aodf.ADDRESS_KEY
WHERE EMPLOYEE_ORIG_DATE.P_COMPANY_ID_I = 3149
If you ask for rewriting to simplify the query, then you may consider using DENSE_RANK() analytic function to include all the matching ties for returning records :
SELECT CITY, STATE, ZipCode, FIRST_NAME, LAST_NAME
FROM
(
SELECT eod.FIRST_NAME,
eod.LAST_NAME,
eod.SSN,
aod.SSN,
aod.CITY,
aod.STATE,
aod.ZipCode,
DENSE_RANK() OVER ( PARTITION BY SSN ORDER BY ORIG_DATE DESC ) ORIG_DATE
FROM EMPLOYEE_ORIG_DATE eod
JOIN ADDRESS_ORIG_DATE aod
ON eod.SSN = aod.SSN
AND eod.ADRESS_KEY = aod.ADDRESS_KEY
WHERE P_COMPANY_ID_I = 3149
)
WHERE ORIG_DATE = 1
where PARTITION BY replaces GROUP BY, and ORIG_DATE DESC replaces MAX(ORIG_DATE)
If you just want the most recent row from ADDRESS_ORIG_DATE for each SSN in EMPLOYEE_ORIG_DATE, then I would expect window functions.
I am guessing you just want one row, even if there are duplicates on the most recent date, so I recommend ROW_NUMBER():
SELECT eod.*, aod.*
FROM EMPLOYEE_ORIG_DATE eod JOIN
(SELECT aod.*,
ROW_NUMBER() OVER (PARTITION BY aod.SSN ORDER BY ORIG_DATE DESC) as seqnum
FROM ADDRESS_ORIG_DATE aod
) aod
ON aod.SSN = eod.SSN
WHERE aod.seqnum = 1 AND
eod.P_COMPANY_ID_I = 3149
Related
I have written the query shown here that combines three tables and returns rows where the at_ticket_num from appeal_tickets is duplicated but against a different at_sys_ref value
select top 100
t.t_reference, at.at_system_ref, at_ticket_num, a.a_case_ref
from
tickets t, appeal_tickets at, appeals_2 a
where
t.t_reference in ('AB123','AB234') -- filtering on these values so that I can see that its working
and t.t_number = at.at_ticket_num
and at.at_system_ref = a.a_system_ref
and at.at_ticket_num IN (select at_ticket_num
from appeal_tickets
group by at_ticket_num
having count(distinct at_system_ref) > 1)
order by
t.t_reference desc
This is the output:
t_reference at_system_ref at_ticket_num a_case_ref
-------------------------------------------------------
AB123 30838974 23641583 1111979010
AB123 30838976 23641583 1111979010
AB234 30839149 23641520 1111977352
AB234 30839209 23641520 1111988003
I want to modify this so that it only returns records where t_reference is duplicated but against a different a_case_ref. So in above case only records for AB234 would be returned.
Any help would be much appreciated.
You want all ticket appeals that have more than one system reference and more than one case reference it seems. You can join the tables, count the occurrences per ticket and then only keep the tickets that match these criteria.
select *
from
(
select
t.t_reference, at.at_system_ref, at.at_ticket_num, a.a_case_ref,
count(distinct a.a_system_ref) over (partition by at.at_ticket_num) as sysrefs,
count(distinct a.a_case_ref) over (partition by at.at_ticket_num) as caserefs
from tickets t
join appeal_tickets at on at.at_ticket_num = t.t_number
join appeals_2 a on a.a_system_ref = at.at_system_ref
) counted
where sysrefs > 1 and caserefs > 1
order by t.t_reference, at.at_system_ref, at.at_ticket_num, a.a_case_ref;
Correction
It seems that SQL Server still doesn't support COUNT(DISTINCT ...) OVER (...). You can count distinct values in a subquery though. Replace
count(distinct a.a_system_ref) over (partition by at.at_ticket_num) as sysrefs,
by
(
select count(distinct a2.a_system_ref)
from appeal_tickets at2
join appeals_2 a2 on a2.a_system_ref = at2.at_system_ref
where at2.at_ticket_num = t.t_number
) as sysrefs,
An alternative workaround is to use DENSE_RANK in two directions (found here: https://stackoverflow.com/a/53518204/2270762):
dense_rank() over (partition by at.at_ticket_num order by a.a_system_ref) +
dense_rank() over (partition by at.at_ticket_num order by a.a_system_ref desc) -
1 as sysrefs,
with data as (
<your query plus one column>,
case when
min() over (partition by t.t_reference)
<>
max() over (partition by t.t_reference)
then 1 end as dup
)
select * from data where dup = 1
I am trying to get the last supplier of an item, by using the MAX function. What I am trying to achieve is showing what the supplier name was for the row with the MAX(Date) for all the stock items (shown below as account links).
The code I am using bring up multiple dates for the same accountlink, and I am struggling to see why. My code is:
SELECT
MAX(TxDate) AS Date,
ST.AccountLink,
V.Account AS Supplier
FROM _bvSTTransactionsFull AS ST
JOIN Vendor V on ST.DrCrAccount = V.DCLink
WHERE Module = 'AP'
AND Id = 'OGrv'
GROUP BY ST.AccountLink, V.Account
ORDER BY AccountLink
But my results look like the below
Try this out
select AccountLink,Supplier,date from(SELECT
ST.AccountLink,
V.Account AS Supplier,
TxDate as [date],
row_number()over(partition by ST.AccountLink order by TxDate desc)rownum
FROM _bvSTTransactionsFull AS ST
JOIN Vendor V on ST.DrCrAccount = V.DCLink
WHERE Module = 'AP'
AND Id = 'OGrv')t
where t.rownum = 1
The group by has been removed and ranking function is used to achieve the output
You need a simple subquery to select the last supplier.
select X.supplier as LastSupplier, X.Date as lastDate, X.AccountLink
from _bvSTTransactionsFull X
where X.Date = (select max(date)
from _bvSTTransactionsFull Y
where Y.AccountLink=X.AccountLink)
The subquery extracts the last date for any accountLink, so you can use it on the outer where condition.
I have this query below:
select
Contact.IndividualID,
Contact.IndividualID as ContactId,
Contact.CaseNumber as CaseID,
[Case].ProgramCode as Benefit,
Contact.Email as EmailAddress,
'' as EmailTo,
Contact.FirstName,
[Case].CaseProgramIndividualStatusCode,
[Case].ReviewDueDate as RenewDueDate,
[Case].ReviewDueDate as BenefitExpirationDate,
[Case].ProgramCode as ProgramCode,
pref.Phone as MobileNumber,
Contact.IsHeadOfHousehold,
row_number() over (partition by Contact.CaseNumber order by Contact.IsHeadOfHousehold desc) as row
from
SOMETABLE_Contact_Dev Contact
inner join
SOMETABLE_Case_Dev [Case] on Contact.IndividualID = [Case].IndividualID and Contact.CaseNumber = [Case].CaseNumber
left join
[SSP RE Preferences] pref on Contact.IndividualID = pref.ContactId
where
(([Case].RenewalTypeCode = 'AC' and [Case].ReviewStatusCode in ('RI','RR')) or
([Case].RenewalTypeCode = 'PS' and [Case].ReviewStatusCode = 'RI')) and
DateDiff(day, getdate(), [Case].ReviewDueDate) = 40 and
Contact.Email is not null and
[Case].ProgramCode in ('KC','KT','CC','MA')
And here's the result set from running this query:
Here's what I'm having trouble with. What I want to do is for when there's a grouping as defined by the partition, I want to put as the EmailTo field the Email Address for the top record of the group (row 1):
When there's no grouping, just use the Email Address for the EmailTo field. What's the best way to go about this?
You could use first_value() over the relevant partition.
e.g., Assuming you mean the same partition as used for row_number, add the following line after your row_number line
FIRST_VALUE(Contact.Email) OVER (partition by Contact.CaseNumber order by Contact.IsHeadOfHousehold desc) AS first_email
The database I'm accessing has two tables I need to query using DB2 SQL, shown here as nametable and addresstable. The query is for finding all of the people with a certain balance due. The addresses are stored in a separate table to keep track of address changes. In addresstable, the latest address is determined by a sequence number (ADDRSEQUENCE). The AddressID field is present in both tables, and is what ties each person to specific addresses. The highest sequence number is the current address. I need that current address for each person and only that one. I know I'm going to have to use MAX somewhere for the sequence number, but I can't figure out how to position it given the join. Here's my current query, which of course returns all addresses...
SELECT NAMETABLE.ACCTNUM AS ACCOUNTNUMBER,
NAMETABLE.NMELASTBUS AS LASTNAME,
NAMETABLE.NAME_FIRST AS FIRSTNAME,
NAMETABLE.BALDUE AS BALANCEDUE,
ADDRESSTABLE.STREETNAME AS ADDR,
ADDRESSTABLE.ADDRLINE2 AS
ADDRLINE2,ADDRESSTABLE.CITYPARISH AS CITY,
ADDRESSTABLE.ADDRSTATE AS STATE,
ADDRESSTABLE.ZIPCODE AS ZIP,
ADDRESSTABLE.ADDIDSEQNO AS ADDRSEQUENCE
FROM NAMETABLE JOIN ADDRESSTABLE ON NAMETABLE.ADDRESSID = ADDRESSTABLE.ADDRESSID
WHERE NAMETABLE.BALANCEDUE >= '50.00'
You can do a sub-select on the MAX(ADDRSEQUENCE) like so:
SELECT
N.ACCTNUM AS ACCOUNTNUMBER
,N.NMELASTBUS AS LASTNAME
,N.NAME_FIRST AS FIRSTNAME
,N.BALDUE AS BALANCEDUE
,A.STREETNAME AS ADDR,
,A.ADDRLINE2 AS
,A.ADDRLINE2
,A.CITYPARISH AS CITY,
,A.ADDRSTATE AS STATE,
,A.ZIPCODE AS ZIP,
FROM NAMETABLE AS N
JOIN ADDRESSTABLE AS A
ON N.ADDRESSID = A.ADDRESSID
WHERE N.BALANCEDUE >= '50.00'
AND A.ADDRSEQUENCE = (
SELECT MAX(ADDRSEQUENCE)
FROM ADDRESSTABLE AS A2
WHERE A.ADDRESSID = A2.ADDRESSID
)
This is pretty quick in DB2.
You can use a row_number and partition by to do this. Something like this:
with orderedaddress as (
select row_number() over (partition by ADDRESSID order by ADDRSEQUENCE desc) as rown,
STREETNAME,ADDRESSID, ... from ADDRESSTABLE
)
select NAMETABLE.ACCTNUM AS ACCOUNTNUMBER,
...
oa.STREETNAME
...
from NAMETABLE JOIN orderedaddress oa on NAMETABLE.ADDRESSID = oa.ADDRESSID
where oa.rown = 1
and NAMETABLE.BALANCEDUE >= '50.00'
I'm querying a single table called PhoneCallNotes. The caller FirstName, LastName and DOB are recorded for each call as well as many other fields including a unique ID for the call (PhoneNoteID) but no unique ID for the caller.
My requirement is to return a list of callers with duplicates removed along with the PhoneNoteID, etc from their most recent entry.
I can get the list of users I want using a Group By on name, DOB and Max(CreatedOn) but how do I include uniqueID (of the most recent entry in the results?)
select O.CallerFName,O.CallerLName,O.CallerDOB,Max(O.CreatedOn)
from [dbo].[PhoneCallNotes] as O
where O.CallerLName like 'Public'
group by O.CallerFName,O.CallerLName,O.CallerDOB order by Max(O.CreatedOn)
Results:
John Public 4/4/2001 4/6/12 16:42
Joe Public 4/12/1988 4/6/12 16:52
John Public 1/2/1950 4/6/12 17:01
Thanks
You can also write what Andrey wrote somewhat more compactly if you select TOP (1) WITH TIES and put the ROW_NUMBER() expression in the ORDER BY clause:
SELECT TOP (1) WITH TIES
CallerFName,
CallerLName,
CallerDOB,
CreatedOn,
PhoneNoteID
FROM [dbo].[PhoneCallNotes]
WHERE CallerLName = 'Public'
ORDER BY ROW_NUMBER() OVER(
PARTITION BY CallerFName, CallerLName, CallerDOB
ORDER BY CreatedOn DESC
)
(By the way, there's no reason to use LIKE for a simple string comparison.)
Try something like that:
;WITH CTE AS (
SELECT
O.CallerFName,
O.CallerLName,
O.CallerDOB,
O.CreatedOn,
PhoneNoteID,
ROW_NUMBER() OVER(PARTITION BY O.CallerFName, O.CallerLName, O.CallerDOB ORDER BY O.CreatedOn DESC) AS rn
FROM [dbo].[PhoneCallNotes] AS O
WHERE
O.CallerLName LIKE 'Public'
)
SELECT
CallerFName,
CallerLName,
CallerDOB,
CreatedOn,
PhoneNoteID
FROM CTE
WHERE rn = 1
ORDER BY
CreatedOn
Assuming that the set of [FirstName, LastName, DateOfBirth] are unique (#shudder#), I believe the following should work, on pretty much every major RDBMS:
SELECT a.callerFName, a.callerLName, a.callerDOB, a.createdOn, a.phoneNoteId
FROM phoneCallNotes as a
LEFT JOIN phoneCallNotes as b
ON b.callerFName = a.callerFName
AND b.callerLName = a.callerLName
AND b.callerDOB = a.callerDOB
AND b.createdOn > a.createdOn
WHERE a.callerLName LIKE 'Public'
AND b.phoneNoteId IS NULL
Basically, the query is looking for every phone-call-note for a particular name/dob combination, where there is not a more-recent row (b is null). If you have two rows with the same create time, you'll get duplicate rows, though.