find the first date after a given date in SQL - postgresql

I have two tables related to vital signs like below:
enter image description here
and have the second table
enter image description here
I want to show the table below:
enter image description here
My problem is when I used with statement in SQL to join the tables, the date sometimes didn't show the first record after the date of admission, but it showed the second or third one like this:
enter image description here
I want to show the first and last record after the admission date.
Can anyone help me with this?
With admissionCTE AS (SELECT DISTINCT on (id) id, dateofadmission:: date as Date_of_admission
WHERE
dateofadmission::date is not NULL
and dateofadmission::date < now()),
first_BMI_CTE AS (select id,bmi, date::date as first_assess
from vital_signs
where vital_signs.bmi is not null
order by
id),
last_BMI_CTE AS(SELECT id, bmi,date
from vital_signs
where bmi is not null AND (id,date::DATE) IN (select id,max(date::DATE) as last_date_assessment
from vital_signs
Group by id))
SELECT DISTINCT on (first_BMI_CTE.id) first_BMI_CTE.id as "ID",
admissionCTE.Date_of_admission::date,
first_BMI_CTE.first_assess as "First_assessment_date",
first_BMI_CTE.bmi as "First BMI",
case
when last_BMI_CTE.obs_datetime::date = first_BMI_CTE.first_assess::date then null
else last_BMI_CTE.obs_datetime
end as "Last_assessment_date",
case
when last_BMI_CTE.obs_datetime::date = first_BMI_CTE.first_assess::date then null
else last_BMI_CTE.bmi end as "Last BMI"
from first_BMI_CTE
left outer join last_BMI_CTE on
last_BMI_CTE.id = first_BMI_CTE.id
left outer join admissionCTE on
admissionCTE.id = first_BMI_CTE.id
where admissionCTE.id is not null
and first_BMI_CTE.first_assess >= admissionCTE.Date_of_admission

Related

T-SQL Question for Getting One Customer Type When There Can be More Than One Value

We have an organization that can have more than one customer type basically. However, what a user wants to see is either the partner or direct type (customer type is either Direct, Partner1, Partner2, or Partner3 but can be direct plus a partner value but only can be one of the partner values). So if a customer is both (ex: Direct and Partner1) they just want the type that is a partner (ex: Partner1). So I tried splitting out partners only into one temp table from a few tables joining together different org data. I have the same query without any limit pulling into a different temp table. Then I calculate count and put that into a temp table. Then I tried gathering data from all the temp tables. That is where I run into trouble and lose some of the customers where the type is direct (I have a image link below for a directcustomer and a customer who is both). I have been out of SQL for a bit so this one is throwing me...I figure the issue is the fact that I have a case statement referencing a table that a direct customer will not exist in (#WLPO). However I am not sure how to achieve pulling in these customers while also only selecting which partner type it is for a customer that has a partner and is also direct. FYI using MSSMS for querying.
If OBJECT_ID('tempdb..#WLPO') IS NOT NULL
DROP TABLE #WLPO
IF OBJECT_ID('tempdb..#org') IS NOT NULL
DROP TABLE #org
IF OBJECT_ID('tempdb..#OrgCount') IS NOT NULL
DROP TABLE #OrgCount
IF OBJECT_ID('tempdb..#cc') IS NOT NULL
DROP TABLE #cc
Select
o.OrganizationID,
o.OrganizationName,
os.WhiteLabelPartnerID,
s.StateName
INTO #WLPO
from [Org].[Organizations] o
join [Org].[OrganizationStates] os on o.OrganizationID=os.OrganizationID --and os.WhiteLabelPartnerID = 1
join [Lookup].[States] s on os.StateID = s.StateID
join [Org].[PaymentOnFile] pof on pof.OrganizationID=o.OrganizationID
where os.WhiteLabelPartnerID in (2,3,4)
and os.StateID in (1, 2, 3)
and o.OrganizationID = 7613
select * from #WLPO
Select
o.OrganizationID,
o.OrganizationName,
os.WhiteLabelPartnerID,
s.StateName
INTO #org
from [Org].[Organizations] o
join [Org].[OrganizationStates] os on o.OrganizationID=os.OrganizationID --and os.WhiteLabelPartnerID = 1
join [Lookup].[States] s on os.StateID = s.StateID
join [Org].[PaymentOnFile] pof on pof.OrganizationID=o.OrganizationID
where 1=1--os.WhiteLabelPartnerID = 1
and os.StateID in (1, 2, 3)
and o.OrganizationID = 7613
select * from #org
Select
OrganizationID,
count(OrganizationID) AS CountOrgTypes
INTO #OrgCount
from #org
where OrganizationID = 7613
group by OrganizationID
select * from #OrgCount
Select distinct
ct.OrganizationID,
ok.OrganizationName,
ct.CountOrgTypes,
case when ct.CountOrgTypes = 2 then wlp.WhiteLabelPartnerID
when ct.CountOrgTypes = 1 then ok.WhiteLabelPartnerID
END AS CustomerTypeCode,
case when ct.CountOrgTypes = 2 then wlp.StateName
when ct.CountOrgTypes = 1 then ok.StateName END As OrgState
INTO #cc
from #org ok
left join #WLPO wlp on wlp.OrganizationID=ok.OrganizationID
join #OrgCount ct on wlp.OrganizationID=ct.OrganizationID
select * from #cc
Select
OrganizationID,
OrganizationName,
CountOrgTypes,
case when CustomerTypeCode = 1 then 'Direct'
when CustomerTypeCode = 2 then 'Partner1'
when CustomerTypeCode = 3 then 'Partner2'
when CustomerTypeCode = 4 then 'Partner3' ELSE Null END AS CustomerType,
OrgState
from #cc
order by OrganizationName asc
DirectCustomer
CustomerwithBoth

Converting rows to columns using crosstab in PostgreSQL not working (relation “table” does not exist)

I need to use the compiled data using CTE and then convert the columns to rows using crosstab(open to other ideas) in the next select statement. Below is the query.
with checked_adgroup AS (
SELECT
ua.new_adgroup,
ua.account,
ua.campaign,
ua.ad_group,
ua."position",
cp.category,
pt.full_value,
FROM unnest_adgroup ua
LEFT JOIN taxonomy_category cp ON ua."position" = cp."position"
LEFT JOIN taxonomy pt ON ua.short_val = pt.short_value AND cp.category = pt.category AND (pt.lob IS NULL OR pt.lob = ua.lob)
)
SELECT *
from crosstab(
'select
cad.account,
cad.campaign,
cad.ad_group,
cad.category,
cad.full_value
FROM checked_adgroup cad
WHERE cad.all_correct AND cad.category IS NOT NULL
ORDER BY 1,2,3')
AS final_result(
account text, campaign text, ad_group text,
division text, lob text, match_type text );
Error message:
ERROR: relation "checked_adgroup" does not exist LINE 7: FROM checked_adgroup cad
Output of checked_adgroup cte looks like below:
enter image description here
Desired output of the final statement is:
enter image description here
Welcome to the community. First off please do not post images, they are useless to work with, and in some instances they are prohibited and cannot be viewed. Instead use formatted text.
I haven't used crosstab functionality all that much, but it does offer a second version which contains 2 queries, the second feeding into the first. There are however a couple errors in your posted query that would need correcting either way. So that first. Look for --<< tag.
with checked_adgroup AS (
SELECT
ua.new_adgroup,
ua.account,
ua.campaign,
ua.ad_group,
ua."position",
cp.category,
pt.full_value,
--<< missing column or ending , above should not be there, assumption missing column see below.
FROM unnest_adgroup ua
LEFT JOIN taxonomy_category cp ON ua."position" = cp."position"
LEFT JOIN taxonomy pt ON ua.short_val = pt.short_value AND cp.category = pt.category AND (pt.lob IS NULL OR pt.lob = ua.lob)
)
SELECT *
from crosstab(
'select
cad.account,
cad.campaign,
cad.ad_group,
cad.category,
cad.full_value
FROM checked_adgroup cad
WHERE cad.all_correct AND cad.category IS NOT NULL
--<< above line has 2 errors:
--<< Incorrectly formatted needs to cad.all_correct is not null AND cad.category IS NOT NULL
--<< column cad.all_correct does not exist (see missing column above
ORDER BY 1,2,3')
AS final_result(
account text, campaign text, ad_group text,
division text, lob text, match_type text);
Now we need to transform the CTE to a second query that crosstab might be ale to use. I have identified each with Postgres $Quoting$, not so much from necessity as standard string quote (') would be sufficant, but more from visibility standing.
select *
from crosstab(
$ct1$select
account,
campaign,
ad_group,
category,
full_value
--<< from checked_adgroup cad
--<< where cad.all_correct and cad.category is not null
--<< moved above lines to second query to avoid reference and removed qualification
order by 1,2,3
$ct1$
, $ct2$select *
from (
select
ua.new_adgroup,
ua.account,
ua.campaign,
ua.ad_group,
ua."position",
cp.category,
pt.full_value,
'mssing from orig posted query' all_correct
from unnest_adgroup ua
left join taxonomy_category cp on ua."position" = cp."position"
left join taxonomy pt on ua.short_val = pt.short_value
and cp.category = pt.category
and (pt.lob is null or pt.lob = ua.lob)
) s
where all_correct is not null and cad.category is not null
--<< move from query1
$ct2$ )
as final_result(
account text, campaign text, ad_group text,
division text, lob text, match_type text );
But at this point I get an error relationship unnest_adgroup does not exist. Which is true as you did not post the definition, not other referenced tables. But that seems to imply the syntax is correct.
Admittedly, this may be way off base if so, so be it, I can always delete later. But, I stuck at home with no other projects at the moment and this seems like an interesting question. Looking forward to the results. Good Luck.

Using a UDF multiple times in a Sproc

I have a SQL 2k5 sproc I'm working with.
I need to reference a UDF to calculate price based on a few variables and the users permissions. I originally tried this, but it didn't work because I wasn't referencing a field...
SELECT dbo.f_GetPrice(model,userid,authType) 'YourPrice', name, description
FROM tblRL_Products
WHERE 'YourPrice' Between #fromPrice AND #toPrice
OR 'YourPrice' IS NULL
So I modified this to
SELECT dbo.f_GetPrice(model,userid,authType) 'YourPrice', name, description
FROM tblRL_Products
WHERE dbo.f_GetPrice(model,userid,authType) Between #fromPrice AND #toPrice
OR dbo.f_GetPrice(model,userid,authType) IS NULL
When SQL executes this sproc, is it running the function 3X's for each record or does it run it the one time and use the values in the other two places per row.
Is there a more efficient way of doing this?
Edit
This is the Scalar UDF. It needs to grab a price based on the type the user is authorized for, then once we have the right price we need to do a calculation on it. This is all stored in the authorization tables. Every user has an authorization for each line of products. So they may have different price types and calculations for each line, returning back dozens or even hundreds of lines in a single search result call.
In the above code I used authType, that was an old call, we don't use that parameter anymore.
ALTER function [dbo].[f_GetPrice]
(
#model uniqueidentifier,
#userID uniqueidentifier
)
returns money
as
begin
Declare #yourPrice money
WITH ProductPrice AS(
SELECT (CASE PriceType
WHEN 'msrp' THEN p.price_msrp
WHEN 'jobber' THEN p.price_jobber
WHEN 'warehouse' THEN p.price_warehouse
WHEN 'margin' THEN p.price_margin
WHEN 'mycost' THEN p.price_mycost
WHEN 'customprice1' THEN p.price_custom1
WHEN 'customprice2' THEN p.price_custom2
WHEN 'customprice3' THEN p.price_custom2
ELSE p.price_msrp
END) as YourPrice, aup.calc, aup.amount
FROM products p
JOIN lines l ON l.lineID=l.lineID
JOIN authorizations a ON l.authlineID=a.authlineID
JOIN authorizationusers au ON a.auID=au.auID
JOIN authorizationuserprices aup ON au.aupID=aup.aupID
WHERE au.userID=#userID AND p.modelID=#model)
SELECT #yourPrice=(CASE calc
WHEN 'amount' THEN YourPrice+amount
WHEN 'percent' THEN YourPrice+(YourPrice*amount/100)
WHEN 'divide' THEN YourPrice/amount
WHEN 'factore' THEN YourPrice*amount
WHEN 'none' THEN YourPrice
ELSE YourPrice
END) FROM ProductPrice
return #yourPrice
END
If you must use a udf for this, then use a subquery and filter outside the subquery:
select YourPrice, name, description
from
(
SELECT dbo.f_GetPrice(model,userid,authType) YourPrice, name, description
FROM tblRL_Products
) d
WHERE YourPrice Between #fromPrice AND #toPrice
OR YourPrice IS NULL
Then you are only calling your udf once instead of 3 times.
Scalar functions are not good, when they have to be applied to a quite number of rows. In this case definitely you can convert your scalar function into table-valued function, which will not be called one time for every row of input data.
create function [dbo].[ft_GetPrice]
(
#model uniqueidentifier,
#userID uniqueidentifier
)
returns table
as return
(
WITH ProductPrice AS (
SELECT (CASE PriceType
WHEN 'msrp' THEN p.price_msrp
WHEN 'jobber' THEN p.price_jobber
WHEN 'warehouse' THEN p.price_warehouse
WHEN 'margin' THEN p.price_margin
WHEN 'mycost' THEN p.price_mycost
WHEN 'customprice1' THEN p.price_custom1
WHEN 'customprice2' THEN p.price_custom2
WHEN 'customprice3' THEN p.price_custom2
ELSE p.price_msrp
END) as YourPrice, aup.calc, aup.amount
FROM products p
JOIN lines l ON l.lineID=l.lineID
JOIN authorizations a ON l.authlineID=a.authlineID
JOIN authorizationusers au ON a.auID=au.auID
JOIN authorizationuserprices aup ON au.aupID=aup.aupID
WHERE au.userID=#userID AND p.modelID=#model
)
SELECT
CASE calc
WHEN 'amount' THEN YourPrice+amount
WHEN 'percent' THEN YourPrice+(YourPrice*amount/100)
WHEN 'divide' THEN YourPrice/amount
WHEN 'factore' THEN YourPrice*amount
WHEN 'none' THEN YourPrice
ELSE YourPrice
END as YourPrice
FROM ProductPrice
)
GO
Which can be used then as:
SELECT fp.YourPrice, name, description
FROM tblRL_Products
outer apply dbo.ft_GetPrice(model, userid, authType) fp
WHERE fp.YourPrice Between #fromPrice AND #toPrice OR fp.YourPrice IS NULL

Why is this field not showing up in the results?

When I run the selects below, I do not get Field3 in the result set, why?
Select
a.Field1,
a.Field2,
a.Field3,
sum(IsNull(a.Field4, 0)) AS SomeAlias1,
a.SomeField5,
a.SomeField6,
a.SomeField7
From SomeTable a
INNER JOIN SomeView1 v on v.au = a.au
inner join (select Username, House from Users userBuildings where UserName = #UserName) as userHouses on userHouses.au = a.au
WHERE
(((where claus logic here....
Group BY a.Field1,
a.Field2,
a.SomeAlias1,
a.Field3,
a.Field4,
a.Field5,
a.Field6,
a.Fielf7
)
Select
transBudget.Field1,
transBudget.Field2,
transDiscount.Field4,
... some other fields...
IsNull(transDiscount.Actual, 0) - IsNull(transBudget.Actual, 0) AS Variance
from (Select * from Transactdions Where TransDesc = 'Budget') AS transBudget
FULL OUTER JOIN
(Select * from Transactions Where TransDesc = 'Discount') AS transDiscount
ON transBudget.Market = transDiscount.Market AND transBudget.SubMarket = transDiscount.SubMarket
I see every field except Field3 for some reason and it's beyond me how the heck this can happen.
In the second part of your query, you are missing field 3.
Select
transBudget.Field1,
transBudget.Field2,
transDiscount.Field4,
... some other fields...
IsNull(transDiscount.Actual, 0)
You appear to have two separate SQL queries there. The first one contains Field3, but the second one does not.

TSQL CTE Error: Incorrect syntax near ')'

I am developing a TSQL stored proc using SSMS 2008 and am receiving the above error while generating a CTE. I want to add logic to this SP to return every day, not just the days with data. How do I do this? Here is my SP so far:
ALTER Proc [dbo].[rpt_rd_CensusWithChart]
#program uniqueidentifier = NULL,
#office uniqueidentifier = NULL
AS
DECLARE #a_date datetime
SET #a_date = case when MONTH(GETDATE()) >= 7 THEN '7/1/' + CAST(YEAR(GETDATE()) AS VARCHAR(30))
ELSE '7/1/' + CAST(YEAR(GETDATE())-1 AS VARCHAR(30)) END
if exists (
select * from tempdb.dbo.sysobjects o where o.xtype in ('U') and o.id = object_id(N'tempdb..#ENROLLEES')
) DROP TABLE #ENROLLEES;
if exists (
select * from tempdb.dbo.sysobjects o where o.xtype in ('U') and o.id = object_id(N'tempdb..#DISCHARGES')
) DROP TABLE #DISCHARGES;
declare #sum_enrollment int
set #sum_enrollment =
(select sum(1)
from enrollment_view A
join enrollment_info_expanded_view C on A.enrollment_id = C.enroll_el_id
where
(#office is NULL OR A.group_profile_id = #office)
AND (#program is NULL OR A.program_info_id = #program)
and (C.pe_end_date IS NULL OR C.pe_end_date > #a_date)
AND C.pe_start_date IS NOT NULL and C.pe_start_date < #a_date)
select
A.program_info_id as [Program code],
A.[program_name],
A.profile_name as Facility,
A.group_profile_id as Facility_code,
A.people_id,
1 as enrollment_id,
C.pe_start_date,
C.pe_end_date,
LEFT(datename(month,(C.pe_start_date)),3) as a_month,
day(C.pe_start_date) as a_day,
#sum_enrollment as sum_enrollment
into #ENROLLEES
from enrollment_view A
join enrollment_info_expanded_view C on A.enrollment_id = C.enroll_el_id
where
(#office is NULL OR A.group_profile_id = #office)
AND (#program is NULL OR A.program_info_id = #program)
and (C.pe_end_date IS NULL OR C.pe_end_date > #a_date)
AND C.pe_start_date IS NOT NULL and C.pe_start_date >= #a_date
;WITH #ENROLLEES AS (
SELECT '7/1/11' AS dt
UNION ALL
SELECT DATEADD(d, 1, pe_start_date) as dt
FROM #ENROLLEES s
WHERE DATEADD(d, 1, pe_start_date) <= '12/1/11')
The most obvious issue (and probably the one that causes the error message too) is the absence of the actual statement to which the last CTE is supposed to pertain. I presume it should be a SELECT statement, one that would combine the result set of the CTE with the data from the #ENROLLEES table.
And that's where another issue emerges.
You see, apart from the fact that a name that starts with a single # is hardly advisable for anything that is not a local temporary table (a CTE is not a table indeed), you've also chosen for your CTE a particular name that already belongs to an existing table (more precisely, to the already mentioned #ENROLLEES temporary table), and the one you are going to pull data from too. You should definitely not use an existing table's name for a CTE, or you will not be able to join it with the CTE due to the name conflict.
It also appears that, based on its code, the last CTE represents an unfinished implementation of the logic you say you want to add to the SP. I can suggest some idea, but before I go on I'd like you to realise that there are actually two different requests in your post. One is about finding the cause of the error message, the other is about code for a new logic. Generally you are probably better off separating such requests into distinct questions, and so you might be in this case as well.
Anyway, here's my suggestion:
build a complete list of dates you want to be accounted for in the result set (that's what the CTE will be used for);
left-join that list with the #ENROLLEES table to pick data for the existing dates and some defaults or NULLs for the non-existing ones.
It might be implemented like this:
… /* all your code up until the last WITH */
;
WITH cte AS (
SELECT CAST('7/1/11' AS date) AS dt
UNION ALL
SELECT DATEADD(d, 1, dt) as dt
FROM cte
WHERE dt < '12/1/11'
)
SELECT
cte.dt,
tmp.[Program code],
tmp.[program_name],
… /* other columns as necessary; you might also consider
enveloping some or all of the "tmp" columns in ISNULLs,
like in
ISNULL(tmp.[Program code], '(none)') AS [Program code]
to provide default values for absent data */
FROM cte
LEFT JOIN #ENROLLEES tmp ON cte.dt = tmp.pe_start_date
;