Can we write subquery in between SELECT and FROM - sql

i want to know, how to write subquery in between SELECT and FROM as
SELECT Col_Name,(Subquery)
From Table_Name
Where Some_condition

This:
SELECT y.col_name,
(SELECT x.column
FROM TABLE x) AS your_subquery
FROM TABLE y
WHERE y.col = ?
...is a typical subquery in the SELECT clause. Some call it a "subselect". This:
SELECT y.col_name,
(SELECT x.column
FROM TABLE x
WHERE x.id = y.id) AS your_subquery
FROM TABLE y
WHERE y.col = ?
...is a correlated subquery. It's correlated because the subquery result references a table in the outer query (y in this case).
Effectively, just write whatever additional SELECT statement you want in the SELECT clause, but it has to be surrounded by brackets.

you can do it, but you must use an alias for the subquery
SELECT Col_Name,(Subquery) as S
From Table_Name
Where Some_condition

Related

Use a subselect within a "locate" function to test for multiple values? Alternatives?

I am looking for a way to run a "locate" function on multiple values based on a subselect; this is the pseudocode I'm envisioning (which does not run, because the subselect returns more than one value; which is what I want).
select * from table
where locate((select distinct field1 from subquery), field2) > 0
This is an unknown number of values, so I cannot use "or" statements for multiple values.
The only way I can think to do it is to do a join on the table to the subselect, but I am worried about efficiency with this method.
with cte_subselect as (select distinct field1 from subquery)
select * from table inner join cte_subselect on 1=1
where locate(field1, field2) > 0
Is the inner join method my only option?
You want to combine all results from the subquery in with the rows of the main table and search for matches. In short, you want to filter over the cross product of a table with a subquery.
The typical solution is to do what you are doing already. Namely:
select t.*
from t
join (select distinct field1 from subquery) x
on locate(x.field1, t.field2) > 0
Now, if performance is important you can speed it up by adding an index:
create index ix1 on t (field2);
Then, the query can be rephrased as:
select t.*
from (select distinct field1 from subquery) s
join t on t.field2 like s.field1 || '%'
Try this instead of inner join.
with cte_subselect as (select distinct field1 from subquery)
select * from table
where (select max(locate(field1, field2) ) from cte_subselect) > 0

How to create a select clause using a subquery

I have the following sql statement:
WITH
subquery AS (
select distinct id from a_table where some_field in (1,2,)
)
select id from another_table where id in subquery;
Edit
JOIN is not an option (this is just a reduced example of a bigger query)
But that obviously does not work. The id field exists in both tables (with a different name, but values are the same: numeric ids). Basically what I want to do is filter by the result of the subquery, like a kind of intersection.
Any idea how to write that query in a correct way?
You need a subquery for the second operand of IN that SELECTs from the CTE.
... IN (SELECT id FROM subquery) ...
But I would recommend to rewrite it as a JOIN.
Are you able to join on ID and then filter on the Where clause?
select a.id
from a.table
inner join b.table on a.id = b.id
where b.column in (1,2)
Since you only want the id from another_table you can use exists
with s as (
select id
from a_table
where some_field in (1,2)
)
select id
from another_table t
where exists ( select * from s where s.id=t.id )
But the CTE is really redundant since all you are doing is
select id
from another_table t
where exists (
select * from a_table a where a.id=t.id and a.some_field in (1,2)
)

Snowflake, SQL where clause

I need to write query with where clause:
where
pl.ods_site_id in (select id from table1 where ...)
But if subquery (table1) didn't return anything, where clause doesn't need to include in result query (like it returns TRUE).
How can I do it? (I have snowflake SQL dialect)
You could include a second condition:
where pl.ods_site_id in (select id from table1 where ...) or
not exists (select id from table1 where ...)
This explicitly checks for the subquery returning no rows.
If you are willing to use a join instead, Snowflake supports qualify clause which might come in handy here. You can run this on Snowflake to see how it works.
with
pl (ods_site_id) as (select 1 union all select 5),
table1 (id) as (select 5) --change this to 7 to test if it returns ALL on no match
select a.*
from pl a
left join table1 b on a.ods_site_id = b.id -- and other conditions you want to add
qualify b.id = a.ods_site_id --either match the join condition
or count(b.id) over () = 0; --or make sure there is 0 match from table1

Why my derived table (subquery) can't have an alias

Sorry for this weird question.
I know that sql has a rule which is "Every derived table must have its own alias." For example:
this is wrong:
SELECT ID FROM (SELECT * FROM (SELECT * FROM IDs));
and it should be:
SELECT ID FROM
(SELECT * FROM (SELECT * FROM IDs)
AS alias) AS anotherAlias;
but my code the as alias is wrong:
SELECT ID FROM tableA
WHERE ID NOT IN
(SELECT ID FROM tableB) AS alias;
A table alias is only needed for a subquery in the FROM clause. Such a subquery is sometimes called a derived table. All derived tables need an alias -- in some (but not all) databases.
In the SELECT clause, a subquery can also take an alias -- but that is a column alias.
In your example, the subquery is not representing any result set or value, so an alias is not needed.
Because you're not using the subquery as a table, you're using it as a collection of values in an IN clause within a WHERE clause.
Your first example has the subquery in the FROM clause.
Think about the reason for the alias. If I write:
SELECT x.*
FROM x
INNER JOIN
(
SELECT *
FROM y
) ON x.id = ???
The query breaks down. I can't refer to any fields in my derived table. Obviously this version works:
SELECT x.*
, y.*
FROM x
INNER JOIN
(
SELECT *
FROM y
) y ON x.id = y.id
In the above, I need to alias y so that I can refer to fields in that derived table.
However, the following query does work without an alias as you mention:
SELECT *
FROM x
WHERE id IN (SELECT id FROM y)
So why does that query work? Well, we don't need the field names of anything in the sub-query. We are just referencing it as a list.
That's why if I write:
SELECT *
FROM x
WHERE id IN (SELECT id, id2 FROM y)
I see an error related to too many fields coming from the sub-query. We can only have one.
Does that help?

Add diferent condition into where clause depending on case condition

If column A is not empty I should add one condition and if it is empty, then I should add another condition. Something like this:
select *
from table t
where case when len(t.A) > 0 then t.A = (select B from anothertable )
else t.C = (select D from anothertable)
As this does not compiles, and I can't use IF clause within WHERE is there any other way to achieve this?
We can rephrase the login in the WHERE clause to make it work:
SELECT *
FROM table_t
WHERE
(LEN(t.A) > 0 AND t.A IN (SELECT B FROM anothertable) ) OR
(LEN(t.A) <= 0) AND t.C IN (SELECT D FROM anothertable) );
To address the comment by #HoneyBadger if the subqueries on anothertable return more than one record, then this query would error out if we used t.A = (subquery). If you intend to use equals, then you would have to ensure that the subquery only returns a single record. Your suggestion to use WHERE IN might fix the problem.