Case when with subquery - sql

I'm trying to create a query that flags every line item that falls into a list of loan numbers that i'm pulling together with a subquery.
So far my script is written as follows:
case when loannumber in
(
select distinct cast(loannumber as float)
from tbl_one
where exists (select a.loannumber,
case when a.FlagA = 0 and b.[NFC] = 'N/A' then 'x'
when a.FlagA = 0 and b.[NFC] <> 'N/A' and sum(a.Amount) > b.[NFC] then 'x'
when a.FlagA = 1 and b.[FC] = 'on approval' then 'x'
when a.FlagA = 1 and b.[FC] <> 'on approval' and sum(a.Amount) > b.[FC]then 'x'
end as [error flag]
from tbl_one a
inner join lkp_table b
on a.State = b.state
group by a.loannumber, FlagA, [NFC], [FC])
)
then 'Error 1' else null end as [Error 1],
When I run the subquery, it correctly identifies all loan numbers that should be flagged, but when I put it into the case when statement, it ends up flagging every loan number in the population. Is there a way to fix this?

Related

Oracle SQL - Case statement with iteration

The ASCII table values should be compared to the s.manure_type. For each record in the following table below the QuantityText case statement should do a comparison. The value it needs to select is e.g. oats,velvet beans, other none.
select
c.id customer_num,
c.type type,
s.id_text sample_num,
c.sasa_grower_code s_grower,
c.address s_address1,
c.postalcode s_post_code,
c.email q1_email,
nvl(c.client_name, c.farm_name )s_company,
c.farm_name s_estate,
c.contact_name s_contact,
s.id_numeric id_numeric,
s.id_text fas_lab_id,
s.date_received received_date,
s.date_printed printed_date,
s.sampled_date sampled_date,
e.name S_AREA_DESCRIP,
a.name s_advisor_name,
a.email s_advisor_email,
s.order_no s_order_num,
s.field_name s_field,
p.phrase_text || ' cm' sample_depth,
cr.crop_name s_crop,
s.attyield s_yield,
s.variety s_varty,
case when s.flg_trashed is null then
'None'
else (case when s.flg_trashed = constant_pkg.get_true then
'Yes'
else (case when s.flg_trashed = constant_pkg.get_false then
'No'
else ' '
end)
end) end trashed,
case when s.flg_irrigated is null then
'None'
else (case when s.flg_irrigated = constant_pkg.get_true then
'Yes'
else (case when s.flg_irrigated = constant_pkg.get_false then
'No'
else ' '
end)
end) end s_irrig,
CASE
WHEN trim(s.manure_type) in (select p.phrase_id from phrase p where p.phrase_type = 'AL_G_MANUR') then (select p.phrase_text from phrase p)
END AS QuantityText,
'' S_GM_YIELD,
s.project_code project_code,
s.trial_ref trial_ref,
s.cost_centre cost_centre
from client c
left outer join sample s on (s.client_id = c.id)
left outer join extension e on (e.id = c.extension_id)
left outer join advisor a on (a.id = c.advisor_id)
left outer join phrase p on (p.phrase_id = s.depth)
left outer join crop cr on (cr.id = s.crop_id)
where p.phrase_type = phrase_pkg.get_soil_depth
and c.id = '211493A'
and s.fas_sample_type = sample_pkg.get_soil_sample
and s.flg_recommendation = sample_pkg.get_flg_recommendation
and s.id_numeric between 14932 and 14933
+----------------------------+
| Phrase |
+----------------------------+
|AL_G_MANUR OA Oats |
|AL_G_MANUR V Velvet Beans
|AL_G_MANUR O Other
|AL_G_MANUR N None |
+----------------------------+
But I get the error ORA-00900: Single row query returns more than one row
Missing where clause in one of the case statements is most likely the cause.
CASE
WHEN trim(s.manure_type) in
(select p.phrase_id from phrase p where p.phrase_type = 'AL_G_MANUR')
then (select p.phrase_text from phrase p) <<< NO WHERE CLAUSE ?
END AS QuantityText,
This is relatively easy to debug yourself.
Remove a single selected column
Check if error still occurs
If it does, go back to 1.
If it does not then verify why last added column errors
Problem is in the following statement
then (select p.phrase_text from phrase p)
I guess, It should be replaced with this
(select p.phrase_text from phrase p where p.phrase_type = 'AL_G_MANUR')

How can I prevent a Lazy Spool from happening in my query?

I been struggling to optimize this query,
SELECT
dbo.OE61BLIN.Order_Key
,dbo.OE61BLIN.Doc_Type
,dbo.OE61BHED.Doc__
,dbo.OE61BHED.Inv_Date
,dbo.OE61BHED.Cust__
,dbo.OE61BLIN.Line_Type
,dbo.OE61BLIN.Item__
,dbo.OE61BLIN.Description
,(CASE
WHEN dbo.OE61BLIN.Doc_Type = 'I' THEN dbo.OE61BLIN.Qty_Shipped * dbo.OE61BLIN.Unit_Factor
WHEN dbo.OE61BLIN.Doc_Type = 'C' AND
dbo.OE61BLIN.return_to_inventory_ = 1 THEN -dbo.OE61BLIN.Qty_Shipped * dbo.OE61BLIN.Unit_Factor
ELSE 0
END) AS QTY
,(CASE
WHEN dbo.OE61BLIN.Doc_Type = 'I' THEN dbo.OE61BLIN.Ext_Price
WHEN dbo.OE61BLIN.Doc_Type = 'C' THEN -dbo.OE61BLIN.Ext_Price
ELSE 0
END) * (CASE
WHEN ISNULL(dbo.OE61BHED.Inv_Disc__, 0) <> 0 THEN 1 - (dbo.OE61BHED.Inv_Disc__ / 100)
ELSE 1
END)
AS amount
,dbo.OE61BHED.Inv_Disc__
,dbo.OE61BLIN.ITEM_GROUP
,dbo.OE61BLIN.Category
,ISNULL(dbo.AR61ACST.intercompany, 0) AS intercompany
FROM dbo.OE61BHED
LEFT OUTER JOIN dbo.AR61ACST
ON dbo.OE61BHED.Cust__ = dbo.AR61ACST.Cust__
RIGHT OUTER JOIN dbo.OE61BLIN
ON dbo.OE61BHED.Order_Key = dbo.OE61BLIN.Order_Key
WHERE (dbo.OE61BLIN.Line_Type = 'R')
AND isnull(intercompany,0) != 1
AND (dbo.OE61BLIN.Doc_Type = 'C'
OR dbo.OE61BLIN.Doc_Type = 'I')
Complete estimated execution plan is here
https://www.brentozar.com/pastetheplan/?id=S1htt0rxN
Actual Exectuion Plan
https://www.brentozar.com/pastetheplan/?id=BymztxLgE
I use SQL Sentry Plan Explorer to optimaze it ,
and it suggested that I should add the following two indexes, which I have
But it doesnt improve much, It only removed RID Look Up from plan.
CREATE NONCLUSTERED INDEX [XI_LineTypeDocType_OE61BLIN_12172018]
ON [dbo].[OE61BLIN] ([Line_Type],[Doc_Type])
INCLUDE ([Order_Key],[Item__],[Description],[Category],[Return_to_Inventory_],[Unit_Factor],[Qty_Shipped],[Ext_Price],[ITEM_GROUP])
CREATE INDEX [XI_CustIntercompany_AR67ACST_12172018] ON [GarbageMark].[dbo].[AR61ACST]
([Cust__] ASC)
INCLUDE ([Intercompany])
I am completely stuck on how to aproach this problem.
I see that Lazy Spool is the most expensive operation but I dont know how to remove
or substitute.
Regrettably you don't prefix intercompany in the where clause with its table name so to some extent I'm guessing that the changes you see below. I am going to suggest that you re-arrange your query to avoid the use of right outer join and then, perhaps more importantly, place the intercompany <> 1 condition directly into the left join which
removes the use of ISNULL() from your where clause.
SELECT
dbo.OE61BLIN.Order_Key
, dbo.OE61BLIN.Doc_Type
, dbo.OE61BHED.Doc__
, dbo.OE61BHED.Inv_Date
, dbo.OE61BHED.Cust__
, dbo.OE61BLIN.Line_Type
, dbo.OE61BLIN.Item__
, dbo.OE61BLIN.Description
, (CASE
WHEN dbo.OE61BLIN.Doc_Type = 'I' THEN dbo.OE61BLIN.Qty_Shipped * dbo.OE61BLIN.Unit_Factor
WHEN dbo.OE61BLIN.Doc_Type = 'C' AND
dbo.OE61BLIN.return_to_inventory_ = 1 THEN -dbo.OE61BLIN.Qty_Shipped * dbo.OE61BLIN.Unit_Factor
ELSE 0
END) AS QTY
, (CASE
WHEN dbo.OE61BLIN.Doc_Type = 'I' THEN dbo.OE61BLIN.Ext_Price
WHEN dbo.OE61BLIN.Doc_Type = 'C' THEN -dbo.OE61BLIN.Ext_Price
ELSE 0
END) * (CASE
WHEN ISNULL( dbo.OE61BHED.Inv_Disc__, 0 ) <> 0 THEN 1 - (dbo.OE61BHED.Inv_Disc__ / 100)
ELSE 1
END)
AS amount
, dbo.OE61BHED.Inv_Disc__
, dbo.OE61BLIN.ITEM_GROUP
, dbo.OE61BLIN.Category
, ISNULL( dbo.AR61ACST.intercompany, 0 ) AS intercompany
FROM dbo.OE61BLIN
INNER JOIN dbo.OE61BHED ON dbo.OE61BLIN.Order_Key = dbo.OE61BHED.Order_Key
LEFT OUTER JOIN dbo.AR61ACST ON dbo.OE61BHED.Cust__ = dbo.AR61ACST.Cust__
AND dbo.AR61ACST.intercompany != 1
WHERE dbo.OE61BLIN.Line_Type = 'R'
AND dbo.OE61BLIN.Doc_Type IN ('C','I')
;
I believe the join between OE61BLIN and OE61BHED can be an inner join, if not try using a left join.

How to use a non-existing column in sql query

I am working in SQL server 2012. I have to write a sql statement where I first assign a value to [Pay_Type], which is a non-existing column (not sure whether it can be called as variable or not) and based upon its value I want to use it in another case statement as shown below
SELECT sp.First_Name, [Pay_Type] = CASE WHEN NOT EXISTS(SELECT '1' FROM
PERSON_SALARY ps WHERE ps.PARTY_ID = sp.PARTY_ID and ps.END_DATE IS NULL)
THEN 'Hourly' ELSE 'Salary' END,
HOURLY_RATE = CASE WHEN [Pay_Type] = 'Hourly' THEN pj.HOURLY_RATE ELSE
'0.00' END
FROM SEC_PERSON sp
LEFT OUTER JOIN PERSON_JOB pj ON sp.PERSON_ID = pj.PERSON_ID
WHERE sp.END_DATE IS NOT NULL
But I am getting "Invalid column name 'Pay_Type' " error.
Column aliases cannot be re-used in the same SELECT where they are define. The typical answer is to use a subquery or CTE. I also like using a lateral join:
SELECT sp.First_Name, s.Pay_Type,
HOURLY_RATE = (CASE WHEN s.Pay_Type = 'Hourly' THEN pj.HOURLY_RATE ELSE
'0.00' END)
FROM SEC_PERSON sp LEFT OUTER JOIN
PERSON_JOB pj
ON sp.PERSON_ID = pj.PERSON_ID OUTER APPLY
(SELECT (CASE WHEN NOT EXISTS (SELECT 1
FROM PERSON_SALARY ps
WHERE ps.PARTY_ID = sp.PARTY_ID and ps.END_DATE IS NULL
)
THEN 'Hourly' ELSE 'Salary'
END) as PayType
) s
WHERE sp.END_DATE IS NOT NULL

Defaulting result in case expression using count

I currently am casing off of a big select statement. I am trying to work through the case portion. I currently have the case set up where it will take the name 'Brad' where units are 'inches'.
If I get rid of the units, it will show more than one result. Is there a way to default in the case statement where the case returns more than one result for 'brad'? Where if there is only 1 result, it will show that result, otherwise if there is more than 1 result, use units = 'inches'?
Here is the working case statement:
And case when R.name = 'Brad' and R.units ='Inches' then 0 else 1 End = 1
Here is a non working semi-psedu version of what I'd like to do:
And case when Count(R.name ='Brad') > 1 then (R.name = 'Brad' and R.units = 'Inches') else (R.name = 'Brad' ) End
Regardless it should return 1 result, default to inches if it returns more than 1 for the name 'Brad'
Here is the portion of the statement how it is joined.
select r.name, r.units, r.blah
From items I
Inner Join Results.R (NoLock)
ON I.Code = R.Code
WHERE r.status IN ('Y','N')
And case when R.name = 'Brad' and R.units ='Inches' then 0 else 1 End = 1

Excel: Incorrect Syntax near the keyword 'SELECT'

Scenario: I am building a report in Excel to calculate commissions. This is based on Invoices from the previous month.
I created the following tsql query and created a connection using MSQuery. I tested the query and it works perfect until I change my Where statement to use the parameter "?" so I can , then I get the following error:
Incorrect Syntax near the keyword `'SELECT'`
Here is the query:
SELECT v_rpt_Invoices.Invoice_Number, v_rpt_Invoices.Territory, v_rpt_Company.Account_Nbr, v_rpt_Invoices.Company_Name, v_rpt_Invoices.Date_Invoice,
v_rpt_Invoices.Location, v_rpt_Invoices.TicketNbr, v_rpt_Invoices.Project_ID, v_rpt_Invoices.Invoice_Type, v_rpt_Invoices.Status_Description,
CASE WHEN TicketNbr <> 0 THEN 'Service Ticket' WHEN Project_ID IS NOT NULL THEN 'Project' ELSE 'Other' END AS Invoice_For,
CASE WHEN ticketNbr <> 0 THEN
(SELECT v_rpt_Service.Board_Name
FROM v_rpt_Service
WHERE v_rpt_Invoices.TicketNbr = v_rpt_Service.TicketNbr) WHEN Project_ID IS NOT NULL THEN Project_ID ELSE 'Other' END AS Service_Board_Project,
CASE WHEN TicketNbr <> 0 THEN
(SELECT Bill_Method
FROM SR_Service
WHERE v_rpt_Invoices.TicketNbr = SR_Service.SR_Service_RecID) WHEN project_id IS NOT NULL THEN
(SELECT PM_Billing_Method_ID
FROM PM_Project
WHERE v_rpt_Invoices.PM_Project_RecID = PM_Project.PM_Project_RecID) ELSE 'NONE' END AS BillingMethod, v_rpt_Invoices.Invoice_Amount,
CASE WHEN (TicketNbr <> 0 AND
(SELECT Bill_Method
FROM SR_Service
WHERE v_rpt_Invoices.TicketNbr = SR_Service.SR_Service_RecID) = 'A') THEN Invoice_Amount * 0.7 WHEN (TicketNbr <> 0 AND
(SELECT Bill_Method
FROM SR_Service
WHERE v_rpt_Invoices.TicketNbr = SR_Service.SR_Service_RecID) = 'F') THEN 0.01 WHEN (project_id IS NOT NULL AND
(SELECT PM_Billing_Method_ID
FROM PM_Project
WHERE v_rpt_Invoices.PM_Project_RecID = PM_Project.PM_Project_RecID) = 'A') THEN Invoice_Amount * 0.7 WHEN (project_id IS NOT NULL AND
(SELECT PM_Billing_Method_ID
FROM PM_Project
WHERE v_rpt_Invoices.PM_Project_RecID = PM_Project.PM_Project_RecID) = 'F') THEN 0.01 ELSE 0.00 END AS Cost
FROM v_rpt_Invoices INNER JOIN
v_rpt_Company ON v_rpt_Invoices.Company_RecID = v_rpt_Company.Company_RecID
**WHERE (v_rpt_Invoices.Date_Invoice >= ?)**
order by Territory, Invoice_For
Remove this line
**WHERE (v_rpt_Invoices.Date_Invoice >= ?)**
That is not valid SQL -- looks like you want to comment use double dash.
Unless you are just putting the ** to show what you changed. In that case you need to have a value where the ? is the SQL won't work.
As an asside, this query could be made much clearer and faster. Consider consolidating sub-queries into a join. For example, the following sub-query
SELECT Bill_Method
FROM SR_Service
WHERE v_rpt_Invoices.TicketNbr = SR_Service.SR_Service_RecID
MUST be called for every row -- if you make this a join you go from O(nm) to O(n+m) Where n is the size of v_rpt_Invoices and m is the size of SR_Service.
This is just one of the potential sub-queries you can optimize.
Here is an example of rolling in the sub-queries to your example
(I can't test so it might have bugs / typos)
SELECT
v_rpt_Invoices.Invoice_Number,
v_rpt_Invoices.Territory,
v_rpt_Company.Account_Nbr,
v_rpt_Invoices.Company_Name,
v_rpt_Invoices.Date_Invoice,
v_rpt_Invoices.Location,
v_rpt_Invoices.TicketNbr,
v_rpt_Invoices.Project_ID,
v_rpt_Invoices.Invoice_Type,
v_rpt_Invoices.Status_Description,
CASE WHEN TicketNbr <> 0 THEN 'Service Ticket'
WHEN Project_ID IS NOT NULL THEN 'Project'
ELSE 'Other'
END AS Invoice_For,
CASE WHEN ticketNbr <> 0 THEN v_rpt_Service.Board_Name
WHEN Project_ID IS NOT NULL THEN Project_ID
ELSE 'Other'
END AS Service_Board_Project,
CASE WHEN TicketNbr <> 0 THEN SR_Service.Bill_Method
WHEN project_id IS NOT NULL THEN PM_Project.PM_Billing_Method_ID
ELSE 'NONE'
END AS BillingMethod, v_rpt_Invoices.Invoice_Amount,
CASE WHEN (TicketNbr <> 0 AND SR_Service.Bill_Method ='A') THEN Invoice_Amount * 0.7
WHEN (TicketNbr <> 0 AND SR_Service.Bill_Method ='F') THEN 0.01
WHEN (project_id IS NOT NULL AND PM_Project.PM_Billing_Method_ID = 'A') THEN Invoice_Amount * 0.7
WHEN (project_id IS NOT NULL AND PM_Project.PM_Billing_Method_ID = 'F') THEN 0.01
ELSE 0.00
END AS Cost
FROM v_rpt_Invoices
INNER JOIN v_rpt_Company ON v_rpt_Invoices.Company_RecID = v_rpt_Company.Company_RecID
LEFT JOIN SR_Service ON v_rpt_Invoices.TicketNbr = SR_Service.SR_Service_RecID
LEFT JOIN PM_Project ON v_rpt_Invoices.PM_Project_RecID = PM_Project.PM_Project_RecID
LEFT JOIN v_rpt_Service ON v_rpt_Invoices.TicketNbr = v_rpt_Service.TicketNbr
WHERE (v_rpt_Invoices.Date_Invoice >= '1/1/2013')
order by Territory, Invoice_For