Create custom field in SELECT if other field is null - sql

This is a seemingly simple thing to do but I can't find any reference to it. I want to add a customized field to my select statement if the value of another field is null. In the below I want to create a field named 'IMPACT' that shows a value of 'Y' if the LOCATION_ACCOUNT_ID field in the subquery is null. How do I do this?
SELECT FIRST_NAME,LAST_NAME,ULTIMATE_PARENT_NAME, IMPACT = IF LOCATION_ACCOUNT_ID IS NULL THEN 'Y' ELSE ''
FROM (SELECT DISTINCT A.FIRST_NAME,
A.LAST_NAME,
B.LOCATION_ACCOUNT_ID,
A.ULTIMATE_PARENT_NAME
FROM ACTIVE_ACCOUNTS A,
QL_ASSETS B
WHERE A.ACCOUNT_ID = B.LOCATION_ACCOUNT_ID(+)

Use CASE instead of IF:
SELECT
FIRST_NAME,
LAST_NAME,
ULTIMATE_PARENT_NAME,
CASE WHEN LOCATION_ACCOUNT_ID IS NULL THEN 'Y' ELSE '' END AS IMPACT
FROM (
SELECT DISTINCT
A.FIRST_NAME,
A.LAST_NAME,
B.LOCATION_ACCOUNT_ID,
A.ULTIMATE_PARENT_NAME
FROM ACTIVE_ACCOUNTS A,
QL_ASSETS B
WHERE A.ACCOUNT_ID = B.LOCATION_ACCOUNT_ID(+)
You should also use LEFT JOIN syntax instead of the old (+) syntax (but that's more of a style choice in this case - it does not change the result):
SELECT
FIRST_NAME,
LAST_NAME,
ULTIMATE_PARENT_NAME,
CASE WHEN LOCATION_ACCOUNT_ID IS NULL THEN 'Y' ELSE '' END AS IMPACT
FROM (
SELECT DISTINCT
A.FIRST_NAME,
A.LAST_NAME,
B.LOCATION_ACCOUNT_ID,
A.ULTIMATE_PARENT_NAME
FROM ACTIVE_ACCOUNTS A
LEFT JOIN QL_ASSETS B
ON A.ACCOUNT_ID = B.LOCATION_ACCOUNT_ID
)
In fact, since you aren't using any of the columns from B in your result (only checking for existence) you can just use EXISTS:
SELECT
FIRST_NAME,
LAST_NAME,
ULTIMATE_PARENT_NAME,
CASE WHEN EXISTS(SELECT NULL
FROM QL_ASSETS
WHERE LOCATION_ACCOUNT_ID = A.ACCOUNT_ID)
THEN 'Y'
ELSE ''
END AS IMPACT
FROM ACTIVE_ACCOUNTS A

Use a case statement:
SELECT FIRST_NAME,
LAST_NAME,
ULTIMATE_PARENT_NAME,
CASE WHEN Location_Account_ID IS NULL THEN 'Y' ELSE '' END AS IMPACT
FROM (
SELECT DISTINCT A.FIRST_NAME,
A.LAST_NAME,
B.LOCATION_ACCOUNT_ID,
A.ULTIMATE_PARENT_NAME
FROM ACTIVE_ACCOUNTS A,
QL_ASSETS B
WHERE A.ACCOUNT_ID = B.LOCATION_ACCOUNT_ID(+)
) a
p.s. also added a alias for your derived table so you wont get an error for that.

I didn't exactly get what you were asking based on your following statement
(that shows a value of 'Y' if the LOCATION_ACCOUNT_ID field in the
subquery is null)
I can suggest that you use an expression.
Put this statement in between your expression.
NVL(B.LOCATION_ACCOUNT_ID,'Y') IMPACT

Related

JOIN AND CASE MORE AN TABLE

I have 2 tables; the first one ORG contains the following columns:
ORG_REF, ARB_REF, NAME, LEVEL, START_DATE
and the second one WORK contains these columns:
ARB_REF, WORK_STREET - WORK_NUM, WORK_ZIP
I want to do the following: write a select query that search in work and see if the WORK_STREET, WORK_ZIP are duplicate together, then you should look at WORK_NUM. If it is the same then output value ' ok ', but if WORK_NUM is not the same, output 'not ok'
I wrote this SQL query:
select
A.ARB_REF, A.WORK_STREET, A.WORK_NUM, A.WORK_ZIP
case when B.B = 1 then 'OK' else 'not ok' end
from
work A
join
(select
WORK_STREET, WORK_ZIP count(distinct , A.WORK_NUM) B
from
WORK
group by
WORK_STREET, WORK_ZIP) B on B.WORK_STREET = A.WORK_STREET
and B.WORK_ZIP = A.WORK_ZIP
Now I want to join the table ORG with this result I want to check if every address belong to org if it belong I should create a new column result and set it to yes in it (RESULT) AND show the "name" column otherwise set no in 'RESULT'.
Can anyone help me please?
While you can accomplish your result by adding a left outer join to the query you've already started, it might be easiest to just use count() over....
with org_data as (
-- do the inner join before the left join later
select * from org1 o1 inner join org2 o2 on o2.orgid = o1.orgid
)
select
*,
count(*) over (partition by WORK_STREET, WORKZIP) as cnt,
case when o.ARB_REF is not null then 'Yes' else 'No' end as result
from
WORK w left outer join org_data o on o.ARB_REF = w.ARB_REF

Adding CASE expression in the correct spot?

I want to change this query:
select
t.AccountA
,t.AccountB
,t.totalNumber
,a.Category
from TableA t
left join Accounts a
on t.ActNum = a.ActNum
left join
(select distinct
s.col1
from (
select ....
from Table
group by...
) st
left join (select S....
group by..
) g on...
left join (select... on ...
) t on ...
where...
)
so that c.AccountB displays "X" if it was a "Y". So I want to do something like
CASE WHEN c.AccountB = 'Y' THEN 'X' ELSE 'c.AccountB END
Except I'm having a problem where some data (a.Category) is coming from the table a, and table a doesn't have a record in it equal to "Y", so the join doesn't get the category data from a. That field is therefore blank. I'm trying to avoid adding it to that table and would rather change the query. How can I do this? What I think would work is:
select
t.AccountA
,t.AccountB
,t.totalNumber
,a.Category
from TableA t
left join ****** (Select CASE WHEN t.AccountB = 'Y' THEN 'X' ELSE 't.AccountB END Accounts a)
on t.ActNum = a.ActNum
left join
(select distinct
col1
from (
select ....
from Table
group by...
) sta
left join (select S....
group by..
) g on...
left join (select... on ...
) t on ...
where...
)
Where I put the CASE expression in the 7th line here by the asterisks ***
Will this return exactly the same records? This is a really long running query and difficult to test so I'm trying to run it as few times as possible, would like some input to help me so this doesn't turn into a 6 hour project.
EDIT: I had a typo, the first columns selected were supposed to reference the first table - I changed it (table "t")
First, this might be as simple as getting rid of the single quote before c.AccountB CASE WHEN c.AccountB = 'Y' THEN 'X' ELSE c.AccountB END Otherwise I'm not quite sure I understand what you want but I'll try:
If you just want to select then:
select
c.AccountA
,CASE WHEN c.AccountB = 'Y' THEN 'X' ELSE c.AccountB END AccountB
,totalNumber
,a.Category
from TableA t
left join Accounts a
on t.ActNum = a.ActNum
left join
...
If instead you want to use this as part of a join you'll have to use it in your join. Since you don't show how "c" is joined, nor how "c" and "a" are related I will try to give an example:
select
c.AccountA
,CASE WHEN c.AccountB = 'Y' THEN 'X' ELSE c.AccountB END AccountB
,totalNumber
,a.Category
from CheckRegister c
left join Accounts a
on a.ActNum = c.AccountA
left join Accounts b
on b.ActNum = CASE WHEN c.AccountB = 'Y' THEN 'X' ELSE c.AccountB END

How to return Yes or No if nested query has result or not in SQL Server?

I have a stored procedure with a nested query that checks whether "category" from the main table matches a "category" in a sub table.
So there can either be one match or none.
How can I return Yes if there is a match and the sub query returns something and No if there is no match and the sub query returns nothing ?
I tried the following which works in general but only if there is a match as otherwise this returns nothing.
My SQL (shortened):
SELECT A.categoryID,
A.category,
A.[description],
(
SELECT 'Yes' AS subscribed
FROM MOC_Categories_Subscribers D
WHERE D.category = A.category
FOR XML PATH(''), ELEMENTS, TYPE
)
FROM MOC_Categories A
If subquery doesn't return any rows then your result will be NULL. Thus you need to check it. In SQL Server you can do this by using functions ISNULL and COALESCE, it depends on version that you're using
SELECT A.categoryID,
A.category,
A.[description],
COALESCE((SELECT TOP 1 'Yes'
FROM MOC_Categories_Subscribers D
WHERE D.category = A.category), 'No') AS Result
FROM MOC_Categories A
SELECT A.categoryID,
A.category,
A.[description],
(
SELECT
case
when count(subscribed) > 0 then 'Yes'
else 'No'
end
FROM MOC_Categories_Subscribers D
WHERE D.category = A.category
)
FROM MOC_Categories A
You can use an outer join, which returns null values if there is no match. Combine with a case to convert to a yes/no value:
SELECT A.categoryID,
A.category,
A.[description],
subscribed = CASE
WHEN D.category IS NOT NULL THEN 'Yes'
ELSE 'No'
END,
FROM MOC_Categories A
LEFT OUTER JOIN MOC_Categories_Subscribers D
ON D.category = A.category

Get rid of duplicate lines in SQL result set

I have 2 tables which I use to get a result set from
select
a.id,
a.test,
a.score,
b.name,
b.person,
b.grade
from table_test a, table_pers b
where a.test=b.test
now the problem is that table b has multiple entries which are all the same but for "passed"... now if passed is yes and no to 1 person I only need the yes result row and only that one otherwise I need the no row and only onw of them if there are multiple.
Any idea on how that could work?
Thanks in advance.
Ok since the case doens't like the group by here is a more detailed view on the select:
select
t.id,
t.tests test,
t.lang,
m.title_TEXT Titel,
m.Sched Schedual,
m.prof profs,
m.date_out Date,
m.sub subject,
m.chan Changes,
case
when m.cha2 = ''
then m.cha1
else m.cha2
end as last_change,
case
when m.datac2 = ''
then m.datac1
else m.datac2
end as Change_date,
t.posp,
t.A1,
t.B1,
t.Failed,
t.analy,
t.vect,
t.cover,
t.typ,
t.circ,
t.deadline
from table_test t, table_pers m where m.test=t.test
The values I look at in t.passed are '1A' and '1B'
If there is a 1A then then I need that row if tehre is only 1B then I need one of those rows.
The complete select has 39 fields.. but those missing are just normal selects no cases or things like that.
You can take advantage of the fact that 'Yes' > 'No', so you could just use:
select a.id,
a.test,
a.score,
b.name,
b.person,
b.grade,
MAX(Passed) AS Passed
from table_test a
INNER JOIN table_pers b
ON a.test = b.test
GROUP BY a.id, a.test, a.score, b.name, b.person, b.grade;
N.B. I have switched your ANSI 89 JOINs to the new ANSI 92 JOIN syntax. This article covers some good reasons for doing so, however it is subjective and the choice is ultimately yours, the result is the same either way.
An alternative, and possibly more rubust solution (if you have other different allowed values for passed) would be:
select a.id,
a.test,
a.score,
b.name,
b.person,
b.grade,
CASE WHEN COUNT(CASE WHEN Passed = 'Yes' THEN 1 END) > 0 THEN 'Yes' ELSE 'No' END AS Passed
from table_test a
INNER JOIN table_pers b
ON a.test = b.test
GROUP BY a.id, a.test, a.score, b.name, b.person, b.grade;
EDIT
There is no reason I know of that CASE won't work in a group by (unless you are using the alias in the group by and not the full case statement), however you could also achieve this using the ROW_NUMBER() function:
SELECT *
FROM ( SELECT t.id,
t.tests test,
t.lang,
m.title_TEXT Titel,
m.Sched Schedual,
m.prof profs,
m.date_out Date,
m.sub subject,
m.chan Changes,
case when m.cha2 = '' then m.cha1 else m.cha2 end as last_change,
case when m.datac2 = ''then m.datac1 else m.datac2 end as aenderungsdatumChange_date,
t.posp,
t.A1,
t.B1,
t.Failed,
t.analy,
t.vect,
t.cover,
t.typ,
t.circ,
t.deadline,
ROW_NUMBER() OVER(PARTITION BY t.ID ORDER BY t.Passed) AS rn
from table_test t
INNER JOIN table_pers m
ON m.test = t.test
) t
WHERE rn = 1
select a.id,
a.test,
a.score,
b.name,
b.person,
b.grade,
Passed
from table_test a
INNER JOIN table_pers b
ON a.test = b.test
where qualify row_number() over (partition by a.id order by passed desc)=1;

Assign a value to a variable in a select statement and then used to find value in nested select statement

I'm getting the error
A SELECT statement that assigns a value to a variable must not be combined with data-retrieval operations.
Here's my SELECT statement.
SELECT A.vendor_id, **#vendor_employee** = A.vendor_employee_id
, B.txt_first_name, B.txt_last_name,
SELECT txt_Vendor_Employee_Detail_Element,
(CASE
WHEN txt_Vendor_Employee_Detail_Value <> ''
AND txt_Vendor_Employee_Detail_Value IS NOT NULL
THEN txt_Vendor_Employee_Detail_Value
ELSE CONVERT(VARCHAR, txt_Vendor_Employee_Detail_Date)
END) AS Vendor_Detail_Element_Value
FROM t_vendor_employee_detail
WHERE vendor_employee_id = **#vendor_employee**)
FROM...
Yes, basically you can't return data and assign variables in the same select statement. What I think you intend to do is a correlated subquery which references an outer value.
That wolud look something like this:
SELECT A.vendor_id, A.vendor_employee_id
, B.txt_first_name, B.txt_last_name,
(SELECT d.txt_Vendor_Employee_Detail_Element
FROM t_vendor_employee_detail d
WHERE d.vendor_employee_id = A.Vendor_employee_id /* references outside the subqquery */)
FROM...
but you are also returning multiple rows in your subquery which should probably be rewritten as a join.
SELECT A.vendor_id, A.vendor_employee_id
, B.txt_first_name, B.txt_last_name,
d.txt_Vendor_Employee_Detail_Element,
(CASE
WHEN D.txt_Vendor_Employee_Detail_Value <> ''
AND d.txt_Vendor_Employee_Detail_Value IS NOT NULL
THEN d.txt_Vendor_Employee_Detail_Value
ELSE CONVERT(VARCHAR, d.txt_Vendor_Employee_Detail_Date)
END) AS Vendor_Detail_Element_Value
FROM vendor_table_A A
INNER JOIN t_vendor_employee_detail d
ON d.vendor_employee_id = A.vendor_employee_id
INNER JOIN vendor_table_B B
ON...
These examples will give you the basic idea but we would really need the whole query to give you a complete solution.
This looks like something that could be rewritten using a JOIN. It's hard to say how without seeing the whole query, but here is an attempt:
SELECT A.vendor_id, A.vendor_employee_id
, B.txt_first_name, B.txt_last_name,
c.txt_Vendor_Employee_Detail_Element,
(CASE
WHEN c.txt_Vendor_Employee_Detail_Value <> ''
AND c.txt_Vendor_Employee_Detail_Value IS NOT NULL
THEN c.txt_Vendor_Employee_Detail_Value
ELSE CONVERT(VARCHAR, c.txt_Vendor_Employee_Detail_Date)
END) AS Vendor_Detail_Element_Value
FROM ...
INNER JOIN t_vendor_employee_detail c
ON c.vendor_employee_id = A.vendor_employee_id
As the error message says, you cannot use a variable in the way you are trying.
You can retrieve and assign data altogether using a merge statement.
Something like this:
DECLARE #ID TABLE (
ID INT
)
MERGE INTO #ID
USING (
select 1 a,2 b,3 c
) as src
ON ( 1 = 2 )
WHEN NOT MATCHED THEN
INSERT (ID)
VALUES (Src.a)
OUTPUT src.b, src.c
;
SELECT * FROM #ID