Postgresql select from based on condition - sql

How to run a given select statement based on condition?
If a condition (which comes from table_A) is true then select from table_B otherwise from table_C. Tables have no common column.
Something like this
select case when table_A.flag=true then
(select * from table_B )
else
(select * from table_C )
end
from table_A where ...
The above one will fail of course : more than one row returned by a subquery used as an expression

Since the columns are the same, you could use a UNION. Something like:
SELECT *
FROM Table_B
WHERE (SELECT flag FROM Table_A) = true
UNION ALL
SELECT *
FROM Table_C
WHERE (SELECT flag FROM Table_A) <> true
I'm assuming here that Table_A has only one row, but you could adjust the subquery in the WHERE conditions to get the flag however you need it.
The basic idea is that you set up the two conditions so that only one of them is true at a time (based on your flag). So, even though it is a UNION, only one part of the query will return results and you either end up with Table_B or Table_C.

Related

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

SQL - concatenated string in where clause not working as expected - Redshift

This is the SQL (Redshift) I am referring to:
SELECT *
FROM table_a
WHERE col_a||col_b NOT IN
(
SELECT col_a||col_b
from table_b
);
There are values in table_a which don't exist in table_b, yet this always evaluates to a No rows.
Any insight?
Use NOT EXISTS, not NOT IN!!! NOT IN will return no rows at all if any value in the subquery is NULL. Plus, you are comparing multiple columns by concatenating them. That is likely to be a bad method because of collisions: ab/c matches a/bc.
So use this:
SELECT a.*
FROM table_a a
WHERE NOT EXISTS (SELECT 1
FROM table_b b
WHERE b.col_a = a.col_a AND b.col_b = a.col_b
);
The sub query might be having a null value, which is failing the not in clause.
Use coalesce to replace null with an appropriate value based on your data. I have used a ~ character in place of null
SELECT *
FROM table_a
WHERE col_a||col_b NOT IN
(
SELECT coalesce (col_a,'~')||coalesce (col_b , '~')
from table_b
);

SQL 0 results for 'Not In' and 'In' when row does exist

I have a table (A) with a list of order numbers. It contains a single row.
Once this order has been processed it should be deleted. However, it is failing to be deleted.
I began investigating, a really simple query is performed for the deletion.
delete from table(A) where orderno not in (select distinct orderno from tableB)
The order number absolutely does not exist in tableB.
I changed the query in SSMS to :
select * from table(A) where orderno not in (select distinct orderno from tableB)
This returned 0 rows. Bare in mind the orderno does exist in tableA.
I then changed the query from "not in" to "In". It still returned 0 rows. How can this be possible that a value is not in a list of values but also not show for the opposite?
Things I have tried:
Two additional developers to look over it.
ltrim(rtrim()) on both the select values.
Various char casts and casting the number as an int.
Has anyone experienced this?
Don't use NOT IN with a subquery. Use NOT EXISTS instead:
delete from tableA
where not exists (select 1 from tableB where tableA.orderno = tableB.orderno);
What is the difference? If any orderno in TableB is NULL, then NOT IN returns NULL. This is correct behavior based on how NULL is defined in SQL, but it is counterintuitive. NOT EXISTS does what you want.
You can use not exists
select *
from table(A) a
where not exists (selet 1 from tableB where orderno = a.orderno);
I have experienced the same.
try joining the two tables tableA and TableB
select * from TableA a
inner join TableB b on a.orderno =b.orderno
This should allow you to get the records and then you can delete the same.

Find deleted rows: Not EXISTS vs Not IN

In my case, I have two table with same structure: TableA & TableB, and what I was trying to do is to find if there is any records only exists in A but not B.
My script was
SELECT * FROM TableA
WHERE NOT EXISTS (
SELECT * FROM TableB
)
While there is 2 records which only exists in A but not B, this script returns nothing. Then I changed into following:
SELECT ID FROM TableA
WHERE ID NOT IN (
SELECT ID FROM TableB
)
This script works successfully and return the 2 records' ID.
My question is: Is this behavior normal? What is the mechanism behind NOT EXISTS and NOT IN?
I have read some other posts comparing NOT EXISTS and NOT IN, and most people suggest using NOT EXISTS in 99.9% scenarios, is this case fall into that 0.1% which NOT EXISTS is not applicable? (I believed it's due to my wrongly usage though, please correct me if that's the case)
If you want to look at all the values in the rows, then use EXCEPT:
SELECT *
FROM TableA
EXCEPT
SELECT *
FROM TableB;
If you want to use NOT EXISTS correctly, then you need a correlation clause:
SELECT a.*
FROM TableA a
WHERE NOT EXISTS (SELECT 1 FROM TableB b WHERE b.id = a.id);
I strongly recommend using NOT EXISTS over NOT IN with a subquery. NOT IN will return no rows at all if b.id is ever NULL. That is usually not what is intended. NOT EXISTS matches the expected semantics.
You need to be careful with the NOT IN expression.
The A NOT IN(B,C,D) expression basically means (A<>B AND A<>C AND A<>D). If any of the values are NULL the whole expression will become NULL.
So, applicable to your example the correct NOT IN expression should be (unless the ID is not nullable column):
SELECT ID FROM TableA
WHERE ID NOT IN (
SELECT ID FROM TableB WHERE ID IS NOT NULL
)

Returning only duplicate rows from two tables

Every thread I've seen so far has been to check for duplicate rows and avoiding them. I'm trying to get a query to only return the duplicate rows. I thought it would be as simple as a subquery, but I was wrong. Then I tried the following:
SELECT * FROM a
WHERE EXISTS
(
SELECT * FROM b
WHERE b.id = a.id
)
Was a bust too. How do I return only the duplicate rows? I'm currently going through two tables, but I'm afraid there are a large amount of duplicates.
use this query, maybe is better if you check the relevant column.
SELECT * FROM a
INTERSECT
SELECT * FROM b
I am sure your posted code would work too like
SELECT * FROM a
WHERE EXISTS
(
SELECT 1 FROM b WHERE id = a.id
)
You can as well do a INNER JOIN like
SELECT a.* FROM a
JOIN b on a.id = b.id;
You can as well use a IN operator saying
SELECT * FROM a where id in (select id from b);
If none of them, then you can use UNION if both table satisfies the union restriction along with ROW_NUMBER() function like
SELECT * FROM (
SELECT *,
ROW_NUMBER() OVER(PARTITION BY id ORDER BY id) AS rn
FROM (
select * from a
union all
select * from b) xx ) yy
WHERE rn = 1;
Note: there's an ambiguity as to what you mean by a duplicate row, and whether you're talking about duplicate keys, or all fields being the same. My answer deals with all fields being the same; some of the others are assuming it's just the keys. It's unclear which you intend.
You might try
SELECT id, col1, col2 FROM a INNER JOIN b ON a.id = b.id
WHERE a.col1 = b.col1 AND a.col2 = b.col2
adding in other columns as necessary. The database engine should be intelligent enough to do the comparisons on the indexed columns first, so it'll be efficient as long as you don't have rows that are different only on lots of non-indexed fields. (If you do, then I don't think anything will do it particularly efficiently.)