Trying to combine Inner Join and two where statements with a Select Max by date and save result into variable - sql

I'm trying to use a inner join to combine 3 tables into one and pull 2 variables based on the most recent date of entry in a medical database.
I'm looking to pull the last location a patient was seen at and the doctor at that visit, which I will pass into another command later in my query. I will save those as #last_location and #doctor_name respectively. I am using #last_date to try to make a select max to get the last visit only for each given patient. However, blank values are passing forward on my variables (both #doctor_name and #last_location). Can anyone help clean this up? Appreciate the help!
My code is:
SELECT #last_location = location_mstr.location_name, #last_date = Substring (CONVERT(CHAR(8), patient_encounter.billable_timestamp, 112), 5, 2) + '/' + Substring (CONVERT(CHAR(8), patient_encounter.billable_timestamp, 112), 7, 2) + '/' + Substring (CONVERT(CHAR(8), patient_encounter.billable_timestamp, 112), 3, 2), #doctor_name = provider_mstr.description
FROM
location_mstr
INNER JOIN patient_encounter ON location_mstr.location_id = patient_encounter.location_id
INNER JOIN provider_mstr ON patient_encounter.rendering_provider_id = provider_mstr.provider_id
Where (patient_encounter.person_id = #person_id) and (#last_date = MAX(#last_date))
I also tried changing the last statement based on some threads here to:
Where #last_date = (SELECT MAX(#last_date) FROM patient_encounter WHERE patient_encounter.person_id = #person_id)

In the where clause of your original query, it looks like you are trying to find the patient_encounter record with the most recent billable_timestamp. The way you are referencing the #last_date variable in the where clause isn't going to do anything.
Instead, you can just get the TOP 1 most recent row and ORDER BY billable_timestamp DESC to get what you're looking for.
I also changed the string expression in your select list that sets #last_date to use the SQL CONVERT function. You can see a list of date formats that CONVERT can do here: http://msdn.microsoft.com/en-us/library/ms187928.aspx
SELECT TOP 1
#last_location = location_mstr.location_name
,#last_date = CONVERT(VARCHAR, patient_encounter.billable_timestamp, 1)
,#doctor_name = provider_mstr.description
FROM location_mstr
INNER JOIN patient_encounter
ON location_mstr.location_id = patient_encounter.location_id
INNER JOIN provider_mstr
ON patient_encounter.rendering_provider_id = provider_mstr.provider_id
WHERE patient_encounter.person_id = #person_id
ORDER BY patient_encounter.billable_timestamp DESC

Related

Single Query To Select Based On Parameters If Or not supplied

I have used SqlDataSource and have a select query based on District & Zone as below
SELECT a.[committee_id] memberid, a.[membername], a.[memberemail], a.[memberdesignation], a.[membercreatedby],b.districtname AS district,b.districtid,c.zone_name AS zone,c.zoneid
FROM [committee_details] a
LEFT JOIN district_master b on b.districtid=a.districtid
LEFT JOIN zone_master c on c.districtid=a.districtid and c.zoneid = a.zoneid
WHERE (a.[membercreatedby] = 'director') AND ((convert(varchar,a.districtid) LIKE '%2%') AND (convert(varchar,a.zoneid) LIKE '%25%')) ORDER BY a.[committee_id] DESC
It's an inline query. I have tried above query but not able to figure out how to Select condition based.
I want if district supplied then Select according to District, if both District & Zone supplied then Select according to both & If nothing supplied then Select All. But should be in single query. How should I do this?
First, fix your query so you are not using meaningless table aliases. Use table abbreviations! I would also drop all the square braces; they just make the query harder to write and to read.
Basically, you want comparisons with NULL in the WHERE clause. I have no idea why your sample code uses LIKE, particularly columns that appear to be numbers. Nothing in the question explains why LIKE is used for the comparison, so the idea is:
SELECT cd.committee_id as memberid, cd.membername,
cd.memberemail, cd.memberdesignation, cd.membercreatedby,
dm.districtname AS district, dm.districtid,
zm.zone_name AS zone, zm.zoneid
FROM committee_details cd LEFT JOIN
district_master dm
ON cd.districtid = dm.districtid LEFT JOIN
zone_master zm
ON zm.districtid = cd.districtid AND
zm.zoneid = cd.zoneid
WHERE cd.membercreatedby = 'director') AND
(cd.districtid = #district or #district is null) AND
(cd.zoneid = #zone or #zone is null)
ORDER BY cd.[committee_id] DESC;
If you were using LIKE, then I would phrase the logic like:
WHERE cd.membercreatedby = 'director') AND
(cast(cd.districtid as varchar(255)) like #district) AND
(cast(cd.zoneid as varchar(255)) like #zone)
And pass in the patterns as '%' when you want all values to match. This assumes that the columns in cd are not NULL. If they can be NULL, then you want an explicit comparison, as in the first example.
If I got the question right then you can use parameters and compare to the column itself if the values are not supplied or not present.
try the following:
SELECT a.[committee_id] memberid, a.[membername], a.[memberemail], a.[memberdesignation], a.[membercreatedby],b.districtname AS district,b.districtid,c.zone_name AS zone,c.zoneid
FROM [committee_details] a
LEFT JOIN district_master b on b.districtid=a.districtid
LEFT JOIN zone_master c on c.districtid=a.districtid and c.zoneid = a.zoneid
WHERE (a.[membercreatedby] = 'director')
AND b.districtname = isnull(nullif(#districtname, ''), b.districtname)
AND c.zone_name = isnull(nullif(#zone_name, ''), c.zone_name)
ORDER BY a.[committee_id] DESC

concatenating one to many values to one line separated by commas in sql join

I have a join which shares a one to many relationship to one table. I would to in stead of returning this value:
125|PROGRAM1|OEM2|1
125|PROGRAM1|OEM2|2
125|PROGRAM1|OEM2|3
I want to return one line like this:
125|PROGRAM1|OEM2|1,2,3
Here is the sql i am running now:
select d.layout_id,d.pgm_nm,d.corp_nm from io_layout_output d
join (select f.program_nm, c.corp_nm from file_config f
join corp_config c
on f.output_id = c.output_id
where f.output_id = 112) b
on d.pgm_nm = b.program_nm and d.corp_nm = b.corp_nm
How would I end up with the correct output?
You need to use a function for that. See LISTAGG
select d.layout_id,
d.pgm_nm,
LISTAGG(d.corp_nm, ', ') as corp_nm
from io_layout_output d
join (select f.program_nm,
c.corp_nm
from file_config f
join corp_config c
on f.output_id = c.output_id
where f.output_id = 112) b
on d.pgm_nm = b.program_nm
and d.corp_nm = b.corp_nm
group by d.layout_id,
d.pgm_nm
EDIT:
Last time I used Oracle you could use LISTAGG using group by. I just looked at the docs and it doesn't mention it anymore. Here is the way if above does not work:
select d.layout_id,
d.pgm_nm,
LISTAGG(d.corp_nm, ', ')
WITHIN GROUP (ORDER BY d.layout_id, d.pgm_nm) as corp_nm
from io_layout_output d
join (select f.program_nm,
c.corp_nm
from file_config f
join corp_config c
on f.output_id = c.output_id
where f.output_id = 112) b
on d.pgm_nm = b.program_nm
and d.corp_nm = b.corp_nm
Note: I'm just showing how to use the function. Did not look at your query at all. Adding this note because your result data does not match the number of columns on your SQL

How to default to a value in SQL to use for a join if conditions aren't met

I hope I can explain this clearly.
I have a four digit NAICS code lookup table that I am trying to join some records to. The root table has a six-digit NAICS code that I trim and compare to the table (emd) that I want to join to. There are three conditions that I want to join to emd on:
State from root table (x) matches emd
The year in the emd table is the max year in emd for that state
The NAICS code in table x matches the NAICS code in table emd
WHEN #3 is not met, I want the query to use '0000' as the NAICS code.
I.E. - If a record from table X with NAICS "6242" and State "AZ" exists, but table emd doesn't have a corresponding row for "AZ' with "6242", I want to use the "AZ" row with "0000".
I will paste the query below. To initially get this to kind of work, on the join to table emd, I added a case statement, basically saying "If the NAICS codes match, use it. Otherwise, use "0000". However, that is creating duplication.
When I test the query and run a query for a state that does have a NAICS code in the table (not 0000), it still returns a row for the '0000' entry for the corresponding state.
Let me know if you need more information! I can't figure this out.
select x.NAICS, x.StateProvince, x.StateProvinceCode,
emd.FinalDemandOutput,
(x.JobsMaintained * isnull(wd.AvgSalary2017, 0)) * emd.FinalDemandOutput TotalEconomicImpact,
(x.HeadcountExtrapolated * isnull(wd.AvgSalary2017, 0)) * emd.FinalDemandOutput TotalEconomicImpact_HC,
st.MinWage,
x.JobsMaintained * isnull(wd.AvgSalary2017, 0) TotalWages,
x.HeadcountExtrapolated * isnull(wd.AvgSalary2017, 0) TotalWages_HC,
from(
select c.CorporationKey, c.SupplierKey, c.SurveyPeriodKey, sp.year, sp.Quarter, sp.QuarterNum, c.Headcount, c.PYAllocatedRevenue,
c.PYAllocatedJob, c.CYAllocatedRevenue, c.extrapolationfactor, left(concat(ic.Code, '000000'), 6) NAICS, sl.Description StateProvince,
sl.StateCode StateProvinceCode,
(jm.Pct * c.Headcount) as JobsMaintained,
c.CSId_, c.CSSupplierId_, c.ImpactFactor3_Annual, ((c.Headcount/c.extrapolationfactor) * c.ImpactFactor3_Annual) HeadcountExtrapolated
from x
left join WageData wd on Substring(left(concat(x.NAICS, '000000'), 6), 1,4) = substring(wd.NAICS, 1, 4)
left join EconomicMultiplierData4DigitNAICS emd on x.StateProvince = emd.statename
and emd.year = (select max(emd2.year) from EconomicMultiplierData4DigitNAICS emd2 where emd2.statename = x.StateProvince)
and (case when Substring(left(concat(x.NAICS, '000000'), 6), 1,4) = substring(emd.NAICS, 1, 4)
then Substring(left(concat(x.NAICS, '000000'), 6), 1,4)
else '0000'
end) = substring(emd.NAICS, 1, 4)
That is incredibly hard to read, but I think you want something like this:
For the join:
left join EconomicMultiplierData4DigitNAICS emd on x.StateProvince = emd.statename
and emd.year = (select max(emd2.year) from EconomicMultiplierData4DigitNAICS emd2 where emd2.statename = x.StateProvince)
and emd.NAICS = x.NAICS
For the Select:
ISNULL(emd.NAICS,'000000')
Left join will return NULL, then you can use ISNULL to instead select your default value of '000000' in that situation.
EDIT: After comment below, this instead may be closer to the desired result:
For the join:
left join EconomicMultiplierData4DigitNAICS emd on x.StateProvince = emd.statename
and emd.year = (select max(emd2.year) from EconomicMultiplierData4DigitNAICS emd2 where emd2.statename = x.StateProvince)
and emd.NAICS = x.NAICS
left join EconomicMultiplierData4DigitNAICS emdFallback on x.StateProvince = emdFallback.statename
and emdFallback.year = (select max(emd2.year) from EconomicMultiplierData4DigitNAICS emd2 where emd2.statename = x.StateProvince)
and emdFallback.NAICS = '000000'
For the Select:
ISNULL(emd.[FieldName],emdFallback.[FieldName]) [FieldName]
This does make the select a bit more tedious, and may need a DISTINCT.
I imagine there is a better/more clever way to do what you want, though I can't think of it at the moment.

SQL - SELECT subquery AS BIT value for EXIST check

I have a problem.
I'm trying to get a BIT value to check whether a person has entered the building last night between 10pm to midnight. When I run the subquery code by itself, it gives me the results I need. As I'm working with SSRS2008 I need for all the results to be in the same stored procedure.
So the problem is, it gives me the bit values somewhat right, for the ones that are obviously false, it gives false, for the ones that are obviously true, it gives true. But for the ones in the middle (the day shift, who leave at 23) it gives the results somewhat random..
Does anyone have a clue?
SELECT DISTINCT TOP 200
Events.LoggedTime,
PTUsers.Name,
PTDoors.PTDoorsID,
PTUsers.AccessLevel,
CAST(CASE
WHEN EXISTS (SELECT Events.LoggedTime
FROM Events
INNER JOIN PTUsers AS PTUsers_1 ON Events.GlobalIndex1 = PTUsers.GlobalRecord
INNER JOIN PTDoors AS PTDoors_1 ON Events.RecordIndex2 + 1 = PTDoors.Address
WHERE (DATEPART(day, Events.LoggedTime) = DATEPART(day, GETDATE() - 1))
AND (DATEPART(hour, Events.LoggedTime) IN (22, 23))
AND (PTDoors_1.PTDoorsID = 14)) THEN 1 ELSE 0 END AS BIT) AS Night
FROM
Events
INNER JOIN
PTUsers ON Events.GlobalIndex1 = PTUsers.GlobalRecord
INNER JOIN
PTDoors ON Events.RecordIndex2 + 1 = PTDoors.Address
WHERE
(PTUsers.Panel = 0)
AND (PTDoors.Panel = 0)
AND (PTDoors.PTDoorsID = 14)
AND (DATEPART(day, Events.LoggedTime) = DATEPART(day, GETDATE()) - 1)
AND (PTUsers.AccessLevel IN (3))
ORDER BY
Events.LoggedTime DESC
#lrd i did the corrections you suggested,
thanks for pointing out the table aliases :)
i removed the cast, so now i get the BIT column. but now the problem is that i get all "1"'s as results.
What baffles me is the that subquery works as it should as a query on it's own. it goes back a day, and displays the entries on that door in the given timeframe.
now i'm trying to compare that information for the same person, meaning - i see a person in the list, arriving yesterday at 6am, check if that person also arrived the day before that between 22 & midnight and return a bit value to display that.
SELECT DISTINCT TOP 200 Events.LoggedTime, PTUsers.Name, PTDoors.PTDoorsID, PTUsers.AccessLevel, CASE WHEN EXISTS
(SELECT Events.LoggedTime
FROM Events INNER JOIN
PTUsers AS PTUsers_1 ON Events.GlobalIndex1 = PTUsers_1.GlobalRecord INNER JOIN
PTDoors AS PTDoors_1 ON Events.RecordIndex2 + 1 = PTDoors_1.Address
WHERE (DATEPART(day, Events.LoggedTime) = DATEPART(day, GETDATE() - 1)) AND (DATEPART(hour, Events.LoggedTime) IN (22, 23)) AND
(PTDoors_1.PTDoorsID = 14)) THEN 1 ELSE 0 END AS BIT
FROM Events INNER JOIN
PTUsers ON Events.GlobalIndex1 = PTUsers.GlobalRecord INNER JOIN
PTDoors ON Events.RecordIndex2 + 1 = PTDoors.Address
WHERE (PTUsers.Panel = 0) AND (PTDoors.Panel = 0) AND (PTDoors.PTDoorsID = 14) AND (DATEPART(day, Events.LoggedTime) = DATEPART(day, GETDATE())
- 1) AND (PTUsers.AccessLevel IN (3))
ORDER BY Events.LoggedTime DESC
I don't think you need a CAST because you are explicitly defining Night as a BIT By setting the result to EXISTS(), which is a bit. I removed the query that was incorrect.
I see your problem. You are not using the correct table alias for your join constraint in your subquery.
It should be:
INNER JOIN PTUsers AS PTUsers_1 ON Events.GlobalIndex1 = PTUsers_1.GlobalRecord
INNER JOIN PTDoors AS PTDoors_1 ON Events.RecordIndex2 + 1 = PTDoors_1.Address
Also,check and make sure you are using the correct values in your join. I would change the following for a test.
FROM Events Events_2
INNER JOIN PTUsers AS PTUsers_1 ON Events_2.GlobalIndex1 = PTUsers_1.GlobalRecord
INNER JOIN PTDoors AS PTDoors_1 ON Events_2.RecordIndex2 + 1 = PTDoors_1.Address

Update table with date conversion failing on Multi-Part Identifier

Thanks to the guys with suggestions on date conversion yesterday, I now have a working SELECT script.
Unfortunately, when I try to turn it into an UPDATE script, I get the dreaded
Msg 4104, Level 16, State 1, Line 25
The multi-part identifier "mbrProject.ID" could not be bound.
The entire script should insert the date from mbrProject into ProjectDates, for each matching ID (mbrProject.[ID] = ProjectDates.[Project_ID]), whilst resolving mixed US & UK format dates in mbrProject, due to users having incorrect country settings when updating the tables (not changeable from my end).
Update ProjectDates
SET ProjectDates.[Start_Date] =
(
select right([Start_Date],4) +
case
when len([Start_Date])=10 then
substring([Start_Date],4,2) + left([Start_Date],2)
else right('0' + left([Start_Date],firstIndex-1),2) +
right('0' + substring([Start_Date],firstIndex+1,secondIndex - firstIndex-1),2)
end
from
(
select mp.[Start_Date], charindex('/',mp.[Start_Date],1) firstIndex,
charindex('/',mp.[Start_Date],charindex('/',mp.[Start_Date],1)+1) secondIndex
from mbrProject mp
join ProjectDates pd
on mp.ID = pd.Project_ID
)A
where mbrProject.[ID] = ProjectDates.Project_ID
)
If I run ONLY the SELECT statement, it works fine, returning the correct values.
i.e Everything from
select right([Start_Date],4) +
case
down to
from mbrProject mp
join ProjectDates pd
on mp.ID = pd.Project_ID
)A
However, as soon as I try to wrap it up in the UPDATE statement, I get the error.
I know that this is down to syntax, but wherever I try to move stuff, I can't quite figure it out.
Any ideas please?
Thanks
Craig
Try this:
UPDATE PR
SET PR.[Start_Date] = A.[Corrected_Start_Date]
FROM ProjectDates PR
JOIN
(
SELECT
[Id],
RIGHT([Start_Date],4) +
CASE
WHEN len([Start_Date])=10
THEN substring([Start_Date],4,2) + LEFT([Start_Date],2)
ELSE RIGHT('0' + LEFT([Start_Date],firstIndex-1),2) +
RIGHT('0' + substring([Start_Date],firstIndex+1,secondIndex - firstIndex-1),2)
END [Corrected_Start_Date]
FROM
(
SELECT
[Id],
[Start_Date],
charindex('/',[Start_Date],1) firstIndex,
charindex('/',[Start_Date],charindex('/',[Start_Date],1)+1) secondIndex
FROM mbrProject
) S
) A
ON A.[ID] = PR.[Project_ID]
(
select mp.[Start_Date], charindex('/',mp.[Start_Date],1) firstIndex,
charindex('/',mp.[Start_Date],charindex('/',mp.[Start_Date],1)+1) secondIndex
from mbrProject mp
join ProjectDates pd
on mp.ID = pd.Project_ID
)A
At the end of the last line here, the names mp, pd, mbrProject and (the inner ProjectDates) no longer exist as table names or aliases. The only name applicable to this row set from here on is A, the alias you've provided.
So you need to include mp.ID in your select list, and then use A.ID in your outer comparison.
Also, not knowing what you're trying to do, I'd just want to make sure you're aware that ProductDates (the table being updated) and pd are referring to two separate instances of that table, an inner one and an outer one. I'm hoping that the final WHERE should be:
where A.[ID] = ProjectDates.Project_ID
The problem is that doing
Update ProjectDates
SET ProjectDates.[Start_Date] = (select ...)
you are trying to set one field of one row to the results of the sub-select statement, which, I presume, is returning multiple values.