Anyway to use IN operator in the SELECT statement? If not, why? - sql

This may come off as a feature request more than anything, but it would be nice if SQL allowed use of the IN operator in a select statement such as the one below. I want to create new_variable intable1based on the ID variable in table2, hence the case statement.
select ID,
case when ID in (select ID
from table2)
then 1
else 0
end as new_variable
from table1
I understand that SQL will give me an error if I run this, but why is that the case? It doesn't seem obvious to me why SQL developers couldn't enable the IN operator to be used outside of the WHERE clause.
Side note: I'm currently using a left join to avoid this issue, so I am not hung up on this.
select ID,
case when ifnull(b.ID, 0) = 0 then 0
else 1
end as variable_name
from table1
left join(select ID from table2) as b
on a.ID = b.ID

SQL definitely supports this:
select ID,
(case when ID in (select ID from table2)
then 1 else 0
end) as new_variable
from table1
Note that there is a comma after id.
This is standard SQL. If your database doesn't support it, it is a feature request (and one that all or almost all databases support).

Related

Why Using COALESCE or CASE keep returning null

I have the following SQL Query :
(SELECT ROUND(SUM(NBTOSUM)/1000000,1) FROM MyTable t2 WHERE t2.ELEMNAME IN ('A','B','C'))
Which works fine.
But Where there is no 'A','B','C' the result of the select is (null)
So to handle it, I did the following :
(SELECT COALESCE(ROUND(SUM(NBTOSUM)/1000000,1),0) FROM MyTable t2 WHERE t2.ELEMNAME IN ('A','B','C'))
And also try :
(SELECT
CASE
WHEN SUM(NBTOSUM)/1000000 IS NULL THEN 0
ELSE ROUND(SUM(NBTOSUM)/1000000,1)
END
FROM MyTable t2 WHERE t2.ELEMNAME IN ('A','B','C'))
But both keep returning null
What am I doing wrong ?
Move the WHERE restrictions to the CASE expression as well:
SELECT ROUND(SUM(CASE WHEN t2.ELEMNAME IN ('A','B','C')
THEN NBTOSUM ELSE 0 END) / 1000000, 1)
FROM MyTable t2;
Note that this trick solves the null problem and also avoids the need for an ugly COALESCE() call.
Your code should work as the SUM aggregation function will generate a single row of output regardless of whether the number of input rows is zero or non-zero. If there are no input rows or the values are all NULL then the output of the SUM will be NULL and then COALESCE would work.
Since you claim it does not then that suggests that there is something else going on in your query that you have not shared in the question.
You have braces around your statement suggesting that you are using it as part of a larger statement. If so, you can try moving the COALESCE to the outer query:
SELECT COALESCE(
(
SELECT ROUND(SUM(NBTOSUM)/1000000,1)
FROM MyTable
WHERE ELEMNAME IN ('A','B','C')
),
0
)
FROM your_outer_query;
That might fix the problem if you are somehow correlating to an outer query but your question makes no mention of that.
fiddle

Using A Count And A Case Statement In One Query

I'm pretty much out of ideas on how to get this to work.I haven't really used SQL in several years so there's a lot I don't remember.
So here is what I would like to happen:
I return the rows where the Code field from table has the value 1208 AND estnumber = 1187216
Run a count on the selection, if 0 run a subquery
If >0 run a different subquery
I didn't get to the subquery part yet because I can't get this to work correctly at all. Right now I just want it to return text.
Here is the latest attempt, I'm actually using db2 but maybe we can ignore that for now and i'll work that part out later because it says the syntax isnt correct, but other validators disagree (if you dont know anything about db2 just use standard sql when giving advice)
SELECT
count(*) AS t
FROM
table
WHERE
(
ESTNUMBER = 1187216
AND CODE = 1208
)
AND CASE WHEN t = 0 THEN 'it is zero' ELSE 'it is not zero' END;
Are you trying to do something like this?
WITH c AS (
SELECT count(*) AS cnt
FROM table
WHERE ESTNUMBER = 1187216 AND CODE = 1208
)
SELECT s1.*
FROM subquery1 s1
WHERE (SELECT cnt FROM c) = 0
UNION ALL
SELECT s2.*
FROM subquery2 s2
WHERE (SELECT cnt FROM c) > 0;
This assumes that the columns returned by the subqueries are compatible (same number, same types).
There are better ways to write this query (notably using EXISTS and NOT EXISTS), but this conforms directly to how you asked the question.
The string value should come up in the select clause and not in the where filter.
SELECT
count(*) AS t,
(CASE WHEN count(*) = 0 THEN 'it is zero' ELSE 'it is not zero' END) display_str
FROM
table
WHERE
(
ESTNUMBER = 1187216
AND CODE = 1208
)
You're thinking like an imperative programmer, not a declarative one. That is, SQL doesn't have sequential execution: it's all or nothing.
So, here's the start, the bit that works:
SELECT count(*) AS t
FROM table
WHERE ESTNUMBER = 1187216 AND CODE = 1208
Now, to check for the value of count(*), you by now know that WHERE isn't going to work. That's because COUNT is an aggregate function. To look at the result of such of function, you use HAVING.
For your CASE to work, you can move it up into the area that can get count(*) results:
SELECT count(*) AS t
(CASE WHEN count(*) = 0 THEN 'it is zero' ELSE 'it is not zero' END) as msg
FROM table
WHERE ESTNUMBER = 1187216 AND CODE = 1208
Note that "t" is an alias you've given the result of count(*). In most SQL implementations, that alias can't be leveraged in the rest of the statement.
Now, for the either or kind of thing, it would be time to reconsider your approach and what you're really after. You'll probably ultimately have both result sets in your statement and choose how the results are served up.
Something like:
select a.id, a.ct, (case when a.ct=0 then b.amt else c.amt end) as amt
from (select id, count(*) as ct from table1) a
left join (select id, sum(amount) as amt from table2) b on a.id=b.id
left join (select id, sum(amount) as amt from table3) c on a.id=c.id
Hope this helps.

SQL: See how many items in a list, return a hit in a table (using LIKE)

For the sake of argument, say I'm looking for first names in a table. And, the table is irregular - no pattern, some people have 2 names, some 3, some it's all run together, whatever.
SELECT
COUNT(*)
FROM
NAME_TABLE N
WHERE
--the list
N.NAME LIKE 'John%'
OR N.NAME LIKE 'Mich%'
OR N.NAME LIKE 'Rob%'
The above would give how many hits - maybe 70 or 70000, who knows. But, what I really want is a response from 0-3.
i.e., how many of my search terms, get a hit in the table.
I could just run the query and pull the entire table of hits, then
use Excel to get the answer.
Or if in a more typical programming language, I could run a loop
that has an x + 1 in it.
But is there a way to do this directly in an SQL query? Specifically T-SQL I guess...very specifically SQL Server 2008, but I'm kinda curious in general.
Your question is not very clear, at least for me, but my magic crystall ball tells me, that eventually you are looking for something like this:
USE master;
GO
SELECT SUM(CASE WHEN PATINDEX('sys%',[name])>0 THEN 1 ELSE 0 END) AS CountOfSys
,SUM(CASE WHEN PATINDEX('plan%',[name])>0 THEN 1 ELSE 0 END) AS CountOfPlan
,SUM(CASE WHEN PATINDEX('spt_%',[name])>0 THEN 1 ELSE 0 END) AS CountOfSpt
FROM sys.objects;
Another approach was to do a
SELECT 'sys%' AS Pattern, COUNT(*) AS CountPattern
FROM ... WHERE [name] LIKE 'sys%'
UNION ALL
SELECT 'plan%',COUNT(*)
...
UNION ALL
...
This would return a list of all your counts in tabular form.
The third chance was to place all your search patterns into a table and use this table in a CROSS JOIN (similar idea then the UNION approach, but more flexible and more generic):
USE master;
GO
DECLARE #tblPattern TABLE(Pattern VARCHAR(100));
INSERT INTO #tblPattern VALUES('sys%'),('plan%'),('spt_%');
SELECT p.Pattern
,SUM(CASE WHEN PATINDEX(p.Pattern,o.[name])>0 THEN 1 ELSE 0 END) AS CountPattern
FROM sys.objects AS o
CROSS JOIN #tblPattern AS p
GROUP BY p.Pattern
You can use a case statement for each name that resolves to 1 if the name exists in the table or 0 if it does not. Then just add them together and the result will be 0-3 i.e. the number of names that exist in the table.
select
case when exists
select 1 from name_table
where name like 'John%'
then 1 else 0 end
+
case when exists
select 1 from name_table
where name like 'Mich%'
then 1 else 0 end
+
case when exists
select 1 from name_table
where name like 'Rob%'
then 1 else 0 end

Joining two datasets with subqueries

I am attempting to join two large datasets using BigQuery. they have a common field, however the common field has a different name in each dataset.
I want to count number of rows and sum the results of my case logic for both table1 and table2.
I believe that I have errors resulting from subquery (subselect?) and syntax errors. I have tried to apply precedent from similar posts but I still seem to be missing something. Any assistance in getting this sorted is greatly appreciated.
SELECT
table1.field1,
table1.field2,
(
SELECT COUNT (*)
FROM table1) AS table1_total,
sum(case when table1.mutually_exclusive_metric1 = "Y" then 1 else 0 end) AS t1_pass_1,
sum(case when table1.mutually_exclusive_metric1 = "Y" AND table1.mutually_exclusive_metric2 IS null OR table1.mutually_exclusive_metric3 = 'Y' then 1 else 0 end) AS t1_pass_2,
sum(case when table1.mutually_exclusive_metric3 ="Y" AND table1.mutually_exclusive_metric2 ="Y" AND table1.mutually_exclusive_metric3 ="Y" then 1 else 0 end) AS t1_pass_3,
(
SELECT COUNT (*)
FROM table2) AS table2_total,
sum(case when table2.metric1 IS true then 1 else 0 end) AS t2_pass_1,
sum(case when table2.metric2 IS true then 1 else 0 end) AS t2_pass_2,
(
SELECT COUNT (*)
FROM dataset1.table1 JOIN EACH dataset2.table2 ON common_field_table1 = common_field_table2) AS overlap
FROM
dataset1.table1,
dataset2.table2
WHERE
XYZ
Thanks in advance!
Sho. Lets take this one step at a time:
1) Using * is not explicit, and being explicit is good. Additionally, stating explicit selects and * will duplicate selects with autorenames. table1.field will become table1_field. Unless you are just playing around, don't use *.
2) You never joined. A query with a join looks like this (note order of WHERE and GROUP statements, note naming of each):
SELECT
t1.field1 AS field1,
t2.field2 AS field2
FROM dataset1.table1 AS t1
JOIN dataset2.table2 AS t2
ON t1.field1 = t2.field1
WHERE t1.field1 = "some value"
GROUP BY field1, field2
Where t1.f1 = t2.f1 contain corresponding values. You wouldn't repeat those in the select.
3) Use whitespace to make your code easier to read. It helps everyone involved, including you.
4) Your subselects are pretty useless. A subselect is used instead of creating a new table. For example, you would use a subselect to group or filter out data from an existing table. For example:
SELECT
subselect.field1 AS ssf1,
subselect.max_f1 AS ss_max_f1
FROM (
SELECT
t1.field1 AS field1,
MAX(t1.field1) AS max_f1,
FROM dataset1.table1 AS t1
GROUP BY field1
) AS subselect
The subselect is practically a new table that you select from. Treat it logically like it happens first, and you take the results from that and use it in your main select.
5) This was a terrible question. It didn't even look like you tried to figure things out one step at a time.

SQL Server WHEN and subqueries

I needed help with a question and what would be the most clean way of doing this in SQL SERVER.
I am basically writing a query that checks if a customer number is inside another subquery then it should return the servicename for that customer number. This is my attempt and it is not working.
Do you guys have any suggestions?
CASE WHEN aa.cust_no in (SELECT Cust_no FROM #Tabl1) THEN (SELECT ServiceName FROM #Tabl1) END AS Target
I get what you're trying to do, but you syntax needs to be changed. You can try a LEFT JOIN.
This query will give you an idea of what your statement should look like
Select tabl1.ServiceName Target
From SomeTable aa
Left Join #Tabl1 tabl1
On aa.cust_no = tabl1.Cust_no
If you want to put something else if a match is not found in #Tabl1, then you will need to use a WHEN, or a COALESCE.
When tabl1.ServiceName Is NOT NULL Then tabl1.ServiceName Else 'Unknown Target' End
OR
Coalesce (tabl1.ServiceName, 'Unknown Target') Target
instead of case expression try select ServiceName in this way:
SELECT
(SELECT TOP 1 ServiceName FROM #Tabl1 where Cust_no = aa.cust_no) AS Target
FROM ...
I think ure missing one parameter look
CASE Expression
WHEN Value1 THEN Result1
WHEN Value2 THEN Result2
ELSE Alternative
END
I hope this could help...
CASE aa.cust_no
WHEN (SELECT Cust_no FROM #Tabl1 WHERE #Tabl1.cust_no) THEN (SELECT ServiceName FROM #Tabl1 WHERE #Tabl1.cust_no)
ELSE 'NO ServiceName'
END AS Target
I believe this should get what you are looking for.
SELECT serviceName
FROM table_A
WHERE cust_no IN (
SELECT cust_no
FROM table_B
);