How to use a non-existing column in sql query - sql

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

Related

Attempting to use result of Case Expression in a join .. need to improve query

I have the following query which allows me to join the TransactionClass tables base on TransactionClassID from either the primary table (Transactions) or TransactionRules based on a condition as below:
SELECT
Description,
TC.Name,
(CASE
WHEN (TR.TransactionRuleId > 0)
THEN TR.TransactionRuleId
ELSE T.TransactionClassId
END) As ClassId
FROM Transactions AS T
LEFT JOIN TransactionRules TR ON T.Description LIKE TR.Pattern
LEFT JOIN TransactionClasses TC ON TC.TransactionClassId =
(CASE
WHEN (TR.TransactionRuleId > 0)
THEN TR.TransactionClassId
ELSE T.TransactionClassId
END)
The query is running on SQL Server,
In effect, it retrieves the correct TransactionClass entry depending on whether or not the join on TransactionRules was successful or not.
The above query works, but I am trying to simplify the query so that I do not have to repeat the CASE expression in two places.
I attempted to capture the result of the case expression in a variable and use that as follows:
SELECT
Description,
x
FROM Transactions AS T
LEFT JOIN TransactionRules TR
ON T.Description LIKE TR.Pattern
LEFT JOIN TransactionClasses TC
ON TC.TransactionClassId = x
WHERE x = (CASE
WHEN (TR.TransactionRuleId > 0)
THEN TR.TransactionRuleId
ELSE T.TransactionClassId
END)
But I get the error:
[S0001][207] Line 8: Invalid column name 'x'.
Where am I going wrong in my attempt to have only one CASE Expression?
CROSS APPLY is a tidy way to reuse a calculated value e.g.
SELECT
[Description]
, TC.[Name]
, Class.Id
FROM Transactions AS T
LEFT JOIN TransactionRules TR ON T.[Description] LIKE TR.Pattern
CROSS APPLY (
VALUES (
CASE
WHEN TR.TransactionRuleId > 0
THEN TR.TransactionRuleId
ELSE T.TransactionClassId
END
)
) AS Class (Id)
LEFT JOIN TransactionClasses TC ON TC.TransactionClassId = Class.Id;

Access alias in CASE statement

I am trying to create a column called DateStartedStatus that utilizes a previously aliased column to compute its value. It should use CurrentStatus to output a value and an error is showing that says "Invalid column name 'CurrentStatus'". How can I access that alias in the below case statement?
SELECT p.[ID]
,p.[Name] as 'ProcurementName'
,p.[FundingDocumentNumber] as 'FundingDocumentNumber'
,p.[Status]
,p.[Comments] as 'Comments'
,p.[isSAVE]
,p.[InWorkDate]
,p.[RoutedDate]
,p.[FundsCertifiedDate]
,p.[AwardedDate]
,p.[TransactionType]
,p.[FNMSStatus]
,p.[Closed]
,p.[Archived]
,p.[Cancelled]
,(CASE
WHEN p.[Status] = 'In Work' THEN 'Pending'
ELSE p.[Status]
END) as CurrentStatus
,(CASE
WHEN CurrentStatus = 'Awarded' THEN p.AwardedDate <-- fails here CurrentStatus not a column
END) as DateStartedStatus
,(SELECT SUM(TotalCost)
FROM ProcurementsRequestLineItems subprlis
LEFT JOIN RequestLineItems subrli ON subprlis.RequestLineItemID = subrli.ID
WHERE ProcurementID = p.ID) as TotalCost
FROM Procurements p
WHERE p.Closed = 0 AND p.Archived = 0;
Use a subquery as suggested by leftjoin, or move the CurrentStatus logic to a CTE. I prefer CTE as they are more legible to me, but I know many prefer a subquery as it is right in the middle of the code, and in a longer query or one with many CTE's that can be a more legible route.
WITH CurrentStatus
AS
(
SELECT
... -- at least one JOIN'able column back to the main query
,(CASE
WHEN p.[Status] = 'In Work' THEN 'Pending'
ELSE p.[Status]
END) as CurrentStatus
FROM ...
)
Using subqueries like this
select ... CASE WHEN CurrentStatus ....
from
( --calculate Current_status here
select ....
CASE
WHEN p.[Status] = 'In Work' THEN 'Pending'
ELSE p.[Status]
END) as CurrentStatus
...
) s
Do not worry, subquery will not add computational complexity, optimizer will remove it if possible.
Another way is nested CASE expressions (query is not readable):
case when case ... some logic here ... end = 'Awarded'
then ...
end
For SQL Server, I would use a CROSS APPLY instead of an subquery, because I prefer it for readability. For one-condition evaluation, I use IIF instead of CASE.
SELECT p.[ID], p.[Name] AS [ProcurementName], p.[FundingDocumentNumber] AS [FundingDocumentNumber],
p.[Status], p.[Comments] AS [Comments], p.[isSAVE], p.[InWorkDate], p.[RoutedDate], p.[FundsCertifiedDate],
p.[AwardedDate], p.[TransactionType], p.[FNMSStatus], p.Closed, p.[Archived], p.[Cancelled],
cur.CurrentStatus, start.DateStartedStatus, tot.TotalCost
FROM Procurements AS p
CROSS APPLY (SELECT IIF(p.[Status] = 'In Work', 'Pending', p.[Status]) AS CurrentStatus) AS cur
CROSS APPLY (SELECT IIF(cur.CurrentStatus = 'Awarded', p.AwardedDate, null) AS DateStartedStatus) AS start
CROSS APPLY (
SELECT SUM(TotalCost) AS name
FROM ProcurementsRequestLineItems AS subprlis
LEFT JOIN RequestLineItems AS subrli ON subprlis.RequestLineItemID = subrli.ID
WHERE ProcurementID = p.ID
) AS tot
WHERE p.Closed = 0 AND p.Archived = 0;
I would also avoid using the reserved word "Status" as a column identifier.

Case statement in multiple conditions?

I want to check the column mr.name, if mr.name is null then i have to replace mr.name as mr.ticket_no. How? Can use if else or case?
select ROW_NUMBER() OVER(ORDER BY mr_user) sl_no,* from (select
mr.name as mr_no,
coalesce(mr.user_id,0) as mr_user
from stock_production_lot lot
left join kg_grn grn on (grn.name = lot.grn_no)
left join kg_department_indent mr on (mr.name = grn.mr_no)
order by mr.user_id) main
where mr_user=65
When i use like this
case when mr.name is null then '' else mr.ticket_no = grn.mr_no as mr_no
it will throw an error
if mr.name = null means i have to replace mr.name = mr.ticket_no. I want to check the column mr.name, if mr.name is null then i have to replace mr.name as mr.ticket_no
You can use coalesce() to replace null with anything:
select ROW_NUMBER() OVER(ORDER BY mr_user) sl_no,* from (select
coalesce(mr.name,mr.ticket_no) as mr_no,
coalesce(mr.user_id,0) as mr_user
from stock_production_lot lot
left join kg_grn grn on (grn.name = lot.grn_no)
left join kg_department_indent mr on (mr.name = grn.mr_no)
order by mr.user_id) main
where mr_user=65
But if you are comfortable with case when then use as below:
select ROW_NUMBER() OVER(ORDER BY mr_user) sl_no,* from (select
(case when mr.name is null then mr.ticket_no else mr.name end) as mr_no,
coalesce(mr.user_id,0) as mr_user
from stock_production_lot lot
left join kg_grn grn on (grn.name = lot.grn_no)
left join kg_department_indent mr on (mr.name = grn.mr_no)
order by mr.user_id) main
where mr_user=65

Arithmetic overflow error converting varchar to data type numeric CASE statement

I am trying to write a query that returns an "Estimated Annual Value", and for this, I am using a Case statement. There are two inner joins involved in the query.
So, the query and gives me result when I am running this piece:
select Users.Id, Name, PhoneNumber, Email, Currency, count(*) as TotalOrders, sum(TotalCustomerAmount) as TotalOrderValue, avg(TotalCustomerAmount) as AverageOrderValue, TsCreate as RegistrationDate, max(TsOrderPlaced) as LastOrderDate, min(TsOrderPlaced) as FirstOrderDate,
CASE
When PromotionsEnabled = 0 then 'Y'
When PromotionsEnabled = 1 then 'n'
else 'undefined'
end as Promotions,
/*CASE
When ((DATEDIFF(day, max(TsOrderPlaced), min(TsOrderPlaced)) >= 6) AND (count(*) > 3)) then ((sum(TotalCustomerAmount)/(DATEDIFF(day, max(TsOrderPlaced), min(TsOrderPlaced))))*365)
Else '-'
end as EstimatedAnnualValue*/
from AspNetUsers with (nolock)
inner join Orders with (nolock) on Orders.UserId = AspNetUsers.Id and Orders.WhiteLabelConfigId = #WhiteLabelConfigId
and Orders.OrderState in (2,3,4,12)
inner join UserWhiteLabelConfigs with (nolock) on UserWhiteLabelConfigs.UserId = AspNetUsers.Id and Orders.WhiteLabelConfigId = #WhiteLabelConfigId
where AspNetUsers.Discriminator = 'ApplicationUser'
group by Users.Id, Name, Number, Currency, Email, TsCreate, PromotionsEnabled
But the problem comes when I am running this with the second CSAE statement, is it because I cannot use the aggregate function before GROUP BY? I am also thinking of using a Subquery
Looking fr some help!!
You need to use aggregation functions. For instance, if you want 'Y' only when all values are 0 or NULL:
(case when max(PromotionsEnabled) = 0 then 'Y'
when max(PromotionsEnabled) = 1 then 'N'
else 'undefined'
end) as Promotions,
I'm not sure if this is the logic you want (because that detail is not in the question). However, this shows that you can use aggregation functions in a case expression.

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')