CASE statement ALIAS comparison - sql

Here is my query:
SELECT DISTINCT v.codi, m.nom, v.matricula, v.data_compra, v.color,
v.combustible, v.asseguranca,
(CASE WHEN lloguer.dataf IS NOT NULL THEN 'Si' ELSE 'Llogat' END) AS Disponible
FROM vehicle v
INNER JOIN model m on model_codi=m.codi
INNER JOIN lloguer on codi_vehicle=v.codi
WHERE Disponible='Si';
What I'm trying to do it's to show only those rows that have the "lloguer.dataf" is not NULL, but it doesn't alow me to use the "Disponible" alias to do the last line comparison.
What can I do?
This is how the info is shown (with some more atribute) without the last line comparison.

The problem is the alias doesnt exists yet. So you have to repeat the full code or create a subquery.
SELECT *
FROM ( .... ) YourQuery
WHERE Disponible='Si';
You can read more details here https://community.oracle.com/thread/1109532?tstart=0

Remove your CASE WHEN from the SELECT block and replace your WHERE clause with:
WHERE lloguer.dataf IS NOT NULL

I'm a TSQL guy by nature, but can you do this?
Select distinct codi, nom,matricula, data_compra, colour, combustible, asseguranca from
(SELECT DISTINCT v.codi, m.nom, v.matricula, v.data_compra, v.color,
v.combustible, v.asseguranca,
(CASE WHEN lloguer.dataf IS NOT NULL THEN 'Si' ELSE 'Llogat' END) AS Disponible
FROM vehicle v
INNER JOIN model m on model_codi=m.codi
INNER JOIN lloguer on codi_vehicle=v.codi)
WHERE Disponible='Si';
As #JuanCarlosOropeza has stated, the alias doesn't exist until the data is initially fetched. This is why you would be able to use the alias in an order by clause without using a subquery, but not in the where clause as the data hasn't been fetched yet.

Related

Using select case on a left join?

I have used a left join on two of my tables. Now I want to use case to identify the records from my left table who don't have a match in the right table. Such records exist and have a null value in the 'id_zeus' column of my join, however when I execute the case, it is as these fields don't exist. Where am I going wrong ? I get "Present" in all my column Disturbance. I am using Oracle SQL developer.
SELECT
CASE DP.ID_PRB
WHEN NULL
THEN 'Absence'
ELSE 'Present' END as Disturbance,
FROM
FIRE.WSITE WI
LEFT JOIN
(SELECT DISTINCT
DPL.ID_PERT as ID_PRB
FROM FIRE.DEPPLAN DPL
GROUP BY DPL.ID_PERT
) DPL
ON WI.ID_PERT = DP.ID_PERT
What is const? You don't seem to need it. The SELECT DISTINCT and GROUP BY are redundant, so use only one of them. And your alias on the subquery is incorrect.
But your problem is the comparison to NULL. It doesn't even match when doing a comparison as you are doing in CASE. You need to use IS NULL:
SELECT (CASE WHEN DP.ID_PRB IS NULL THEN 'Absence' ELSE 'Present'
END) as Disturbance,
FROM FIRE.WSITE WI LEFT JOIN
(SELECT DISTINCT DPL.ID_PERT as ID_PRB
FROM FIRE.OSI_DEVIATION_PLANS DP
) DP
ON WI.ID_PERT = DP.ID_PERT;
This query would commonly be written as:
SELECT (CASE WHEN NOT EXISTS (SELECT 1
FROM FIRE.OSI_DEVIATION_PLANS DP
WHERE WI.ID_PERT = DP.ID_PERT
)
THEN 'Absence' ELSE 'Present'
END) as Disturbance,
FROM FIRE.WSITE WI ;
This offers more opportunities for optimization.

SQL Inner Join and nearest row to date

I dont't get it. I changed some of the code. In the WPLEVENT Table are a lot of Events per person. In the Persab-Table are the Persons with their History. Now I need the from the Persab Table just that row wich matches the persab.gltab Date nearest to the WPLEVENT.vdat Date. So all rows from the WPLEVENT, but just the one matching row from the PERSAB-Table.
SELECT
persab.name,
persab.vorname,
vdat,
eventstart,
persab.rc1,
persab.rc2
FROM wplevent
INNER JOIN
persab ON WPLEVENT.PersID = persab.PRIMKEY
INNER JOIN
(SELECT TOP 1 persab.rc1
FROM PERSAB
WHERE persab.gltab <= getdate() --/ Should be wplevent.vdat instead of getdate()
) NewTable ON wplevent.persid = persab.primkey
WHERE
persid ='100458'
ORDER BY vdat DESC
Need to use the MAX() function with the proper syntax by supplying an expression like MAX(persab.rc1). Also need to use GROUP BY for the second column rc2 in the subquery (although it looks like you do not need it). Finally you are missing the ON clause for the final INNER JOIN. I can update the answer to fix the query if you provide that information.
SELECT
Z1PERS.NAME
, Z1PERS.VORNAME
, WPLEVENT.VDat
, WPLEVENT.EventStart
, WPLEVENT.EventStop
, WPLEVENT.PEPGROUP
, Z1SGRP.TXXT
, PERSAB.GLTAB
, Z1PERS.PRIMKEY AS Expr1
, PERSAB.PRIMKEY
FROM
Z1PERS
INNER JOIN
WPLEVENT ON Z1PERS.PRIMKEY = WPLEVENT.PersID
INNER JOIN
Z1SGRP ON WPLEVENT.PEPGROUP = Z1SGRP.GRUPPE
INNER JOIN
(
SELECT MAX(Persab.rc1) --Fixed MAX expression
, persab.rc2
FROM
persab
GROUP BY
persab.rc2 --Need to group on rc2 if you want that column in the query otherwise remove this AND the rc2 column from select list
WHERE
WPLEVENT.PersID = PERSAB.PRIMKEY
AND WPLEVENT.VDat <= PERSAB.GLTAB
) --Missing ON clause for the INNER JOIN here
WHERE z1pers.vorname = 'henning'

error is Reason for Column is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause

I got an error
Column 'Employee.EmpID' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
SQL code:
with cte(stu_id,term_cd, spcl_cd ) as
(
Select
zt.[STU_ID], zt.TERM_CD, zt.SPCL_CD
From
SR0TZT(nolock) zt
Inner Join
(Select
STU_ID, MIN(TERM_SEQ_NUM) MinPoint, SPCL_CD
From SR0TZT
Group By STU_ID) tbl1 On zt.STU_ID = tbl1.STU_ID
Where
tbl1.MinPoint = zt.TERM_SEQ_NUM
and zt.STU_ID = '202716354'
and tbl1.SPCL_CD = zt.SPCL_CD
)
SELECT
zt.[STU_ID], zt.[TERM_CD], zt.[SPCL_CD],
zt.[SPCL_STRT_TERM], zt.TERM_SEQ_NUM, t.term_id
FROM
SR0TZT zt
JOIN
cte ON zt.STU_ID = cte.stu_id
WHERE
zt.STU_ID = '202716354'
Condition is:
For each unique combination of TZT.STU_ID and TZT.SPCL_CD where TZT.COLL_CD = '', display the TZT.TERM_CD with the minimum TZT.TERM_SEQ_NUM.
For UID 202716354, based on the above rule, the value of this column is incorrect for both specialization codes.
Not sure I understand why you are getting an error for 'Employee.EmpID' as it doesn't appear in your query.
At first look I can see that the following part of your SQL code (the derived table 'tbl1')...
Select STU_ID,MIN(TERM_SEQ_NUM) MinPoint,SPCL_CD From SR0TZT Group By STU_ID
..is incorrect and would cause a similar error because SPCL_CD isn't used in an aggregate function (such as MIN) or in the GROUP BY. You should change it to:-
Select STU_ID,MIN(TERM_SEQ_NUM) MinPoint,SPCL_CD From SR0TZT Group By STU_ID, SPCL_CD
And that should solve your problem.
Your problem is in this below script:
Select STU_ID,MIN(TERM_SEQ_NUM) MinPoint,SPCL_CD From SR0TZT Group By STU_ID
It should be:
Select STU_ID,MIN(TERM_SEQ_NUM) MinPoint,SPCL_CD From SR0TZT Group By STU_ID, SPCL_CD
Every column that you put in select, you should put them too in group by.

SQL Server Select Distinct and Order By with CASE

I've seen quite a few questions/forum posts regarding this scenario but I either don't understand the solutions or the solutions provided are too specific to that particular question and I don't know how to apply it to my situation. I have the following query:
SELECT DISTINCT d.*
FROM Data d
JOIN Customers c
ON c.Customer_Name = d.Customer_Name
AND c.subMarket = d.subMarket
JOIN Sort s
ON s.Market = c.Market
ORDER BY d.Customer_Name, d.Category, d.Tab, d.SubMarket,
CASE s.sortBy
WHEN 'Comp_Rank'
THEN d.Comp_Rank
WHEN 'Market_Rank'
THEN d.Market_Rank
ELSE d.Other_Rank
END
I used that exact query on my MySQL database and it worked perfectly. We recently switched over to a SQL Server database and now it doesn't work and I get the error:
ORDER BY items must appear in the select list if SELECT DISTINCT is specified.
I've tried adding s.* to the SELECT (since s.sortBy is in the CASE) and that didn't change anything and I also tried listing out every single field in Data and Sort in SELECT and that resulted in the same exact error.
There actually aren't duplicates in Data, but when I do the joins it results in 4 exact duplicate rows for every single item and I don't know how to fix that so that's why I originally added the DISTINCT. I tried variations of LEFT JOINs, INNER JOINs, etc... and couldn't get a different result. Anyway, a solution to either issue would be fine but I'm assuming more information would be needed to figure out the JOIN duplicate issue.
Edit: I just realized that I mistakenly typed some of the fields in the ORDER BY (example, n.Category, n.Tab should have been d.Category, d.Tab). EVERYTHING in the ORDER BY is from the Data table which I've selected * from. As I said, I also tried listing out every field in the SELECT and that didn't help.
As the error suggests, when you use select distinct, you have to order by the expressions in the select clause. So, your case is an issue as well as all the columns not from d.
You can fix this by using group by instead, and including the columns that you want to sort by. Because the case includes a column from s, you need to include the case (or at least that column) in the group by:
SELECT d.*
FROM Data d JOIN
Customers c
ON c.Customer_Name = d.Customer_Name AND
c.subMarket = d.subMarket JOIN Sort s
ON s.Market = c.Market
GROUP BY "d.*",
(CASE s.sortBy WHEN 'Comp_Rank' THEN d.Comp_Rank
WHEN 'Market_Rank' THEN d.Market_Rank
ELSE d.Other_Rank
END)
ORDER BY d.Customer_Name, d.Category, d.Tab, d.SubMarket,
(CASE s.sortBy WHEN 'Comp_Rank' THEN d.Comp_Rank
WHEN 'Market_Rank' THEN d.Market_Rank
ELSE d.Other_Rank
END)
Note that "d.*" is in quotes. You need to list out all the columns in the group by.
Try this:
SELECT DISTINCT d.Customer_Name, d.Category, d.Tab, d.SubMarket,
CASE s.sortBy
WHEN 'Comp_Rank'
THEN d.Comp_Rank
WHEN 'Market_Rank'
THEN d.Market_Rank
ELSE
d.Other_Rank
END
FROM Data d
JOIN Customers c
ON c.Customer_Name = d.Customer_Name
AND c.subMarket = d.subMarket
JOIN Sort s
ON s.Market = c.Market
ORDER BY d.Customer_Name, d.Category, d.Tab, d.SubMarket,
CASE s.sortBy
WHEN 'Comp_Rank'
THEN d.Comp_Rank
WHEN 'Market_Rank'
THEN d.Market_Rank
ELSE
d.Other_Rank
END
Just to follow up on this, you just need to add the case to your SELECT with an AS. Then include that reference in the ORDER BY list.
SELECT DISTINCT d.*, case when ... then ... else ... end AS MyCase
...
ORDER BY d.Customer_Name, d.Category, d.Tab, d.SubMarket, MyCase
This answer is similar to Pang's, but I find not having to include the case statement in both the top and bottom better as errors could arise if you modified one and not the other.

How do I INSERT INTO where many fields have their own Select Statements?

I created a table and i am in the process of inserting rows from another table into it. However, some of these rows require joins from other tables. To my knowledge, this means using a subquery select statement in the statement. the problem is subqueries only return one result, where i may have many. I am wanting to return a -1 where no records exists. Here is an example i am using but it is not working:
INSERT INTO [BDW_ReportPrototype].[dbo].[CustomerCreditFact]
( [MortgageDimID]
,[LeaseDimID]
,[OREODimID]
,[OfficerTypeDimID] )
SELECT
--[MortgageDimID]
-2
--LeaseDimID
,-2
--OREODimID
,-2
,CASE WHEN OfficerTypeDimID IS NULL THEN -1 ELSE OfficerTypeDimID END
FROM Staging_FDB_LN_CPDM_Daily LCD
LEFT OUTER JOIN ERMA..OfficerTypeDim OTD on OTD.OfficerNum = LCD.OFFICER
FROM dbo.Staging_FDB_LN_CPDM_Daily
Try this sql statement
SELECT CASE WHEN OfficerTypeDimID IS NULL THEN -1 ELSE OfficerTypeDimID END
FROM Staging_FDB_LN_CPDM_Daily LCD
LEFT OUTER JOIN ERMA..OfficerTypeDim OTD on OTD.OfficerNum = LCD.OFFICER
I would rework your query like the following.
First of all, use a LEFT OUTER JOIN in your query instead of the subqueries. This type of join says a row might exist in the "other" table but it might not but I want a row back regardless.
Now that you know you'll have all your rows, you'll want to see if there is a value there or not. Use the shorthand and easier to maintain check via the coalesce function. It basically is a list of values (column names, variables or hard coded values) and the optimizer will pick the first non-null value from the list and use it. Here we supply -1 for your query
INSERT INTO
[BDW_ReportPrototype].[dbo].[CustomerCreditFact]
(
[OfficerTypeDimID]
)
SELECT
-- coalesce returns the first non-null value
COALESCE(OTD.OfficerTypeDimID, -1) AS OfficerTypeDimID
FROM
dbo.Staging_FDB_LN_CPDM_Daily LCD
LEFT OUTER JOIN
ERMA..OfficerTypeDim OTD
ON OTD.OfficerNum = LCD.OFFICER
maybe something along these lines...
INSERT INTO [BDW_ReportPrototype].[dbo].[CustomerCreditFact]
([OfficerTypeDimID])
Select OfficerTypeDimID
from ERMA..OfficerTypeDim OTD
inner JOIN Staging_FDB_LN_CPDM_Daily LCD
on OTD.OfficerNum = LCD.OFFICER
UNION ALL
SELECT -1
FROM dbo.Staging_FDB_LN_CPDM_Daily LCD
WHERE NOT EXISTS
(
Select OfficerTypeDimID from ERMA..OfficerTypeDim
OTD
WHERE
OTD.OfficerNum = LCD.OFFICER
)