How to return multiple fields from subquery - sql

I work in healthcare where we check a patient's insurance to see if their insurance is still active and is eligible for our services. Unfortunately, the database is not very good at associating the eligibility with an appointment or future visit (we have no control over this). As a result, we do not have visibility into what ultimately happens as a result of that eligibility check (did we use that insurance? did the patient not use insurance at all? etc).
What we'd like to do is try to associate the eligibility to a patient's visit that is within a day of that eligibility check (so same day or day before). I'd like to retrieve that visit number and the primary payer for that visit (I'd like the visit number so I can verify that I'm pulling in the correct visit as well as the correct primary payer).
How do I get both pieces of information in the results of my main query? Alternative: how can I spot check the results to verify it is working as desired if I'm only returning the payer name from an inline subquery?
Eligibility Query
select distinct
elig.patient_id,
pm.payer_name,
elig.status,
elig.reject_reason
from
eligibility elig
inner join payer_mstr pm on elig.payer_id=pm.payer_id
where
elig.create_timestamp>='2019-01-01' and elig.create_timestamp<'2019-02-01'
Associated Encounter and Payer Data and Tables
select distinct
pe.enc_nbr,
pm.payer_name
from
patient_encounter pe --visit data
--encounter_payer holds payer data for a specific visit, and 1 means primary payer
left join encounter_payer epay on pe.enc_id=epay.enc_id and cob=1
left join payer_mstr pm on epay.payer_id=pm.payer_id
I'm on Microsoft SQL Server 2008 R2

You could try using a common table expression. Works like a subquery and you can add all the fields you would like to have from it.
Common Table Expressions
WITH cte AS (
select
pe.enc_nbr,
pm.payer_name,
pm.payer_id,
ROW_NUMBER() OVER(PARTITION BY pm.payer_id ORDER BY pm.payer_id ASC) AS row_num --If you have a date created on each row I would change the pm.payer_id field that and change it to ORDER BY <field> DESC
from
patient_encounter pe --visit data
--encounter_payer holds payer data for a specific visit, and 1 means primary payer
left join encounter_payer epay on pe.enc_id=epay.enc_id and cob=1
left join payer_mstr pm on epay.payer_id=pm.payer_id
--Here you could add a WHERE clause to narrow your search date down to get previous or current date if you have a date field just use WHERE date >= DATEADD(d,-1,GETDATE())
)
select distinct
elig.patient_id,
pm.payer_name,
elig.status,
elig.reject_reason,
cte.enc_nbr
from
eligibility elig
inner join payer_mstr pm on elig.payer_id=pm.payer_id
left join cte ON cte.pm.payer_id = pm.payer_id --Now you can pull in any fields you need and can see if they have a record or do not
where
elig.create_timestamp>='2019-01-01' and elig.create_timestamp<'2019-02-01'

Hard to test your very specific question, but try this:
SELECT DISTINCT
elig.patient_id,
pm.payer_name,
elig.status,
elig.reject_reason
pe.enc_nbr
FROM
patient_encounter pe
LEFT JOIN encounter_payer epay on pe.enc_id=epay.enc_id and cob=1
LEFT JOIN payer_mstr pm on epay.payer_id=pm.payer_id
LEFT JOIN eligibility elig on elig.payer_id=pm.payer_id
WHERE
elig.create_timestamp>='2019-01-01' and elig.create_timestamp<'2019-02-01'

Related

SQL Query Creates Duplicated Results

My task is to produce a report that shows the on time delivery of products to consumers. In essence I have achieved this. However, as you will see only some of the data is accurate.
Here is our test case: we have a sales order number '12312.' This sales order has had 5 partial shipments made (200 pieces each). The result is shown below from our DUE_DTS table.
Due Dates table data
The following code gives me the information I need (excluding due date information) to show the packing details of the 5 shipments:
DECLARE #t AS TABLE (
CUSTNAME char(35),
SONO char(10),
INVDATE date,
PACKLISTNO char(10),
PART_NO char(25),
SOBALANCE numeric(9,2)
)
INSERT INTO #t
SELECT DISTINCT c.CUSTNAME, s.SONO, p.INVDATE, p.PACKLISTNO, i.PART_NO, q.SOBALANCE
FROM [manex].[dbo].[SODETAIL]
INNER JOIN [manex].[dbo].[SOMAIN] s ON s.SONO = SODETAIL.SONO
INNER JOIN [manex].[dbo].[CUSTOMER] c ON c.CUSTNO = s.CUSTNO
INNER JOIN [manex].[dbo].[INVENTOR] i ON i.UNIQ_KEY = SODETAIL.UNIQ_KEY
INNER JOIN [manex].[dbo].[DUE_DTS] d ON d.SONO = s.SONO
INNER JOIN [manex].[dbo].[PLMAIN] p ON p.SONO = s.SONO
INNER JOIN [manex].[dbo].[PLDETAIL] q ON q.PACKLISTNO = p.PACKLISTNO
WHERE s.SONO LIKE '%12312'
SELECT * FROM #t
Here is a screenshot of the results from running this query:
Query Result
Now is when it should be time to join my due dates table (adding in the appropriate column(s) to my table definition and select statement) and make DATEDIFF comparisons to determine if shipments were on time or late. However, once I reference the due dates table, each of the 5 shipments is compared to all 5 dates in the due dates table, resulting in 25 rows. The only linking column DUE_DTS has is the SONO column. I've tried using DISTINCT and variations of the group by clause without success.
I've put enough together myself to figure joining the DUE_DTS table on SONO must be causing this to happen, as there are 5 instances of that value in the table (making it not unique) and a join should be based on a unique column. Is there a workaround for something like this?
You will need to use additional fields to join the records and reduce the results. You may need to link SONO to SODETAIL to DUE_DTS because the dates are tied to the items, not to the SONO.

Most efficient way to get records from a table for which a record exists in another table for each month

I have two tables as below:
User: User_ID, User_name and some other columns (has approx 1000 rows)
Fee: Created_By_User_ID, Created_Date and many other columns (has 17 million records)
Fee table does not have any index (and I can't create one).
I need a list of users for each month of a year (say 2016) who have created at least one fee record.
I do have a working query below which is taking long time to execute. Can someone help me with a better query? May be using EXIST clause (I tried one but still takes time as it scans Fee table)
SELECT MONTH(f.Created_Date), f.Created_By_User_ID
FROM Fees f
JOIN [User] u ON f.Created_By_User_ID= u.User_ID
WHERE f.Created_Date BETWEEN '2016-01-01' AND '2016-12-31'
You will require a full scan of the fee table once in the original query you are using. If you use just the join directly, as you have in the original query, you will require multiple scans of the fee table, many of which will go through redundant rows while the join occurs. Same scenario will occur when you use an inner query as suggested by Mansoor.
An optimization could be to decrease the number of rows on which the joins are happening.
Assuming that the user table contains only one record per user and the Fee table has multiple records per person, we can attempt to find distinct months users made a purchase for by using a CTE.
Then we can make a join on top of this CTE, this will reduce the computation performed by the join and should give a slightly better output time when performing over a large data set.
Try this:
WITH CTE_UserMonthwiseFeeRecords AS
(
SELECT DISTINCT Created_By_User_ID, MONTH(Created_Date) AS FeeMonth
FROM Fee
WHERE Created_Date BETWEEN '2016-01-01' AND '2016-12-31'
)
SELECT User_name, FeeMonth
FROM CTE_UserMonthwiseFeeRecords f
INNER JOIN [User] u ON f.Created_By_User_ID= u.User_ID
Also, you have not mentioned that you require the user names and all, if only id is required for the purpose of finding distinct users making purchases per month, then you can just use the query within the CTE and not even require the JOIN as:
SELECT DISTINCT Created_By_User_ID, MONTH(Created_Date) AS FeeMonth
FROM Fee
WHERE Created_Date BETWEEN '2016-01-01' AND '2016-12-31'
Try below query :
SELECT MONTH(f.Created_Date), f.Created_By_User_ID
FROM Fees f
WHERE EXISTS(SELECT 1 FROM [User] u WHERE f.Created_By_User_ID= u.User_ID
AND DATEDIFF(DAY,f.Created_Date,'2016-01-01') <= 0 AND
DATEDIFF(DAY,f.Created_Date,'2016-12-31') >= 0
You may try this approach to reduce the query run time. however, It does duplicate the huge data and store a instance of table (Temp_Fees), On every DML performed on table Fees/User require truncate and fresh load of table Temp_Fees.
Select * into Temp_Fees from (SELECT MONTH(f.Created_Date) as Created_MONTH, f.Created_By_User_ID
FROM Fees f
WHERE f.Created_Date BETWEEN '2016-01-01' AND '2016-12-31' )
SELECT f.Created_MONTH, f.Created_By_User_ID
FROM Temp_Fees f
JOIN [User] u ON f.Created_By_User_ID= u.User_ID

Including NULL results after join

I am trying to do a report which shows all payments we have received and for the report I have to show names of patients who pay, but this table also contains checks from payers (insurance companies) and after I do a join all of the payers are excluded. I have tried every join version I know left, right, outer, inner, and combinations of the two. SQL Server 2005.
UPDATE
The line that is causing the left join not to work is
select p.*, max(episode_id) over (partition by patient_id) as maxei from patient p
which I am using in the join. Our system uses an episodic system, so if a patient leaves and comes back they get a new episode. The payment table does not have an episode field though, so I used that line of code in the join to only show the current episode. Any idea how I can keep it only showing the current episode while not losing the fields without patient_id's? Examples of the fields without patients id's are shown in the second image.
select
pay.patient_id,
p.lname + ', ' + p.fname as 'Name',
pay.source_type,
pay.instrument,
pay.doc_reference,
pay.instrument_date,
pay.payment_amount,
pay.user_id,
pay.entry_chron,
pay.payor_id
from payment pay
join (select p.*, max(episode_id) over (partition by patient_id) as maxei from patient p) p
on p.patient_id = pay.patient_id
where episode_id = maxei and (pay.instrument_date between '2014-11-01' and '2014-11-30')
order by pay.payment_amount
This is what the results look like for patients with some fields commented out for confidentiality.
These are the fields that are being excluded

Needing 2 different ID's from the same ID Table

I am pulling reports for my company and am needing to pull a specific report that I am having trouble with. We are using SQL Server 2012 and I am pulling the SQL reports.
What I need is to pull a simple report:
Group Name, List of Members in the group; Supervisor of the group.
However, the problem is that the supervisor as well as the members and the group name all come from one table in order to get the relevant information. Currently here is my SQL code below:
Use DATABASE
go
-- This is the select portion deciding the columns needed.
select
C.group_name
,C2.first_name
,C2.last_name
-- These are the tables that the query is pulling from.
FROM db..groups AS G
LEFT OUTER JOIN db..contact AS C
ON G.group_id=C.contact_id
INNER JOIN db..contact AS C2
ON G.member=C2.contact_id
go
This pulls the first portion:
The group name, then the first name of a member in that group, and then the last name of a member in that group.
However, I am having trouble getting the supervisor portion. This portion uses the table db.contact under the column supervisor_id as a foreign key. The supervisor_id uses the same unique id as the normal contact_id, but in the same table. Some contact_ids have supervisor_id's that are other contact_id's from the same table, hence the foreign key.
How can I make it so I can get the contact_id that is equal to the supervisor_id of the contact_id that is equal to the group_id?
Taking a quick stab at this while we wait for details
You know you need groups and I'm assuming you don't care about Groups that have no members. Thus Groups INNER JOINed to Contact. This generates your direct group membership. To get the supervisor, you then need to factor in the Supervisor on the specific Contact row.
You might not have a boss, or your boss might be yourself. It's always interesting to see how various HR systems record this. In my example, I'm assuming the head reports to no one instead of themselves.
SELECT
G.group_name
, C.first_name
, C.last_name
-- this may produce nulls depending on outer vs inner join below
, CS.first_name AS supervisor_first_name
, CS.last_name AS supervisor_last_name
FROM
dbo.Groups AS G
INNER JOIN
dbo.Contact AS C
ON C.contact_id = G.member
LEFT OUTER JOIN
dbo.Contact AS CS
ON CS.contact_id = C.supervisor_id;
Depending on how exactly you wanted that data reported, there are various tricks we could use to report that data. In particular, GROUPING SETS might come in handy.
SQLFiddle

Return max date from multiple tables join oracle

I have 4 tables with the following relevant information I want to retrieve.
Table: Staff_profile (STAFF_ID, STAFF_USERNAME, STAFF_NAME, STAFF_JOB_ID, STAFF_FACULTY_ID, STAFF_OFF_TEL, STAFF_EMAIL) - holds staff information
Table: RFMUSERHISTORY (uh_staff_id, UH_DATETIME) - holds login history
Table: RFMUSERROLEJOBMAP (role_id, job_id ) - maps role-2-job [this is because job table pre-exists and this new app is only picking certain job ids to use against its own roles table
Table: RFMUSERROLE (USERROLE_CODE, USERROLE_ID) - holds user roles information
Now I want to get the last login (max date for that user in userhistory) details including role and staff details for any particular person who logs in. I have had trouble with my code and finally just resorted to selecting all the records for that user with the UH_datetime ordered desc so I can pick that latest topmost record.
Here is my current code (very inefficient as described above):
SELECT a.STAFF_ID, a.STAFF_USERNAME, a.STAFF_NAME, a.STAFF_JOB_ID, a.STAFF_FACULTY_ID,
a.STAFF_OFF_TEL, a.STAFF_EMAIL, to_CHAR(b.UH_DATETIME,'Dy DD-MM-YYYY HH24:MI:SS')
AS UH_DATETIME, e.USERROLE_CODE, e.USERROLE_ID
FROM STAFF_PROFILE a
LEFT JOIN RFMUSERHISTORY b ON STAFF_ID=b.uh_staff_id
LEFT JOIN RFMUSERROLEJOBMAP d ON a.STAFF_JOB_ID=d.job_id
LEFT JOIN RFMUSERROLE e ON d.role_id=e.userrole_id
WHERE STAFF_ID=:eid1 ORDER BY b.UH_DATETIME DESC
You could use an analytic function to rank the rows and then select the most recent one. If you're really just selecting the data for a single STAFF_ID, this is probably no more efficient than nesting your original query in an outer query that selects the row using a ROWNUM predicate. If you are selecting the data for multiple staff members, however, this should be more efficient.
SELECT *
FROM (
SELECT a.STAFF_ID,
a.STAFF_USERNAME,
a.STAFF_NAME,
a.STAFF_JOB_ID,
a.STAFF_FACULTY_ID,
a.STAFF_OFF_TEL,
a.STAFF_EMAIL,
to_CHAR(b.UH_DATETIME,'Dy DD-MM-YYYY HH24:MI:SS') AS UH_DATETIME,
e.USERROLE_CODE,
e.USERROLE_ID,
dense_rank() over (partition by a.staff_id order by b.uh_datetime desc) rnk
FROM STAFF_PROFILE a
LEFT JOIN RFMUSERHISTORY b ON STAFF_ID=b.uh_staff_id
LEFT JOIN RFMUSERROLEJOBMAP d ON a.STAFF_JOB_ID=d.job_id
LEFT JOIN RFMUSERROLE e ON d.role_id=e.userrole_id
WHERE STAFF_ID=:eid1
)
WHERE rnk = 1
Oracle doesn't send rows over the network before you ask for them. If your client code only request the first row, your query should be efficient enough.
Another option is to limit Oracle to one row with rownum:
where rownum = 1