This is the structure of my existing SQL query :
SELECT * FROM (
SELECT *, 'A' AS Status FROM Table1
WHERE Field1 NOT IN
(
SELECT Field1 FROM Table2 WHERE Field 1 = 'val' AND ...
)
UNION
SELECT *, 'B' AS Status FROM Table1
WHERE Field1 IN
(
SELECT Field1 FROM Table2 WHERE Field 1 = 'val' AND ...
)
) AS Result
Here I'm selecting two sets of data from a table and assigning two different values (A & B) for the Status column and Union both sets in to one as Result.
Problem with this method is, it needs to duplicate the inner select query SELECT Field1 FROM Table2 WHERE Field 1 = 'val' AND ... (my original sql query is bit complex than the shown above)
How can I rewrite this as a single Select query? Is it possible or not?
You could simply move the WHERE condition to a CASE expression, like this:
SELECT
*,
CASE
WHEN Field1 IN (
SELECT Field1 FROM Table2 WHERE Field1 = 'val' AND ...
)
THEN 'B'
ELSE 'A'
END AS Status
FROM Table1
;
You could also use a LEFT JOIN method like others suggested, but if Table2 produces duplicates for the specified filter, you might get duplicates in the output as well. To avoid that, you would probably need to use a derived table that only returns distinct values, something like this:
SELECT
t1.*,
CASE
WHEN t2.Field1 IS NULL THEN 'A'
ELSE 'B'
END AS Status
FROM Table1 t1
LEFT JOIN (
SELECT DISTINCT Field1 FROM Table2 WHERE Field1 = 'val' AND ...
) t2
ON t1.Field1 = t2.Field2
;
you can simply use LEFT JOIN on this,
SELECT a.*,
CASE WHEN b.field1 IS NULL
THEN 'A'
ELSE 'B'
END AS Status
FROM table1 a
LEFT JOIN table2 b
ON a.field1 = b.field1 AND
b.field1 = 'VAL'
Please check the below query, which works if there is only one condition of Field1=’val’ on Table2. If there are multiple where conditions, then go for LEFT JOIN.
SELECT
*,
(CASE WHEN Field1='val' THEN 'B' ELSE 'A' END) AS Status
FROM
Table1
U can achieve this by using LEFT JOIN and CASE as follows
SELECT a.*,
(CASE b.Field1
WHEN 'Val'
THEN 'B' ELSE 'A' END) as status
FROM Table1 a LEFT JOIN Table2 b ON a.field1 =b.field1
If multiple conditions are there for status try the following one
SELECT a.*,
(CASE
WHEN (SELECT COUNT(Field1)
FROM Table2
WHERE field1 =a.field1 AND Field 1 ='val' AND ...) >0
THEN 'B' ELSE 'A' END) as status
FROM Table1 a LEFT JOIN Table2 b ON a.field1 =b.field1
Related
I am new to SQL. I have 2 tables]
Table 1:
id product location
1 banana costco
2 apple walmart
3 lemons target
Table 2:
id
1
2
4
I want to join these 2 tables based on id. If there is a match, I want to create a new column in resultant table so that my result looks like this
id flag
1 true
2 true
3 false
4 true
i.e if the id exists in table2, I want to flag as true else false. I want to include all ids in the resultant table
How can I do this in SQL (Running in Athena)?
I can join through following but I don't know to create a column based on a match
SELECT t2.id from table2 t2,
LEFT JOIN table1 t1 ON t1.id=t2.id
What you are looking for is a full outer join, but MySQL is one of the very few RDBMS that don't support full outer joins.
A full outer join would look like this:
SELECT
COALESCE(t1.id, t2.id) AS id,
(t1.id IS NOT NULL AND t2.id IS NOT NULL) AS flag
FROM table1 t1
FULL OUTER JOIN table2 t2 ON t2.id = t1.id
ORDER BY COALESCE(t1.id, t2.id);
Here are two alternative approaches:
Collect all IDs, then check whether they exist in both tables:
SELECT
id
id IN (SELECT id FROM table1)
AND
id IN (SELECT id FROM table2) AS flag
FROM
(
SELECT id FROM table1
UNION
SELECT id FROM table2
) ids
ORDER BY id;
SELECT the matches, the missing table2 IDs, and the missing table1 IDs, then union these results.
SELECT id, true AS flag FROM table1 JOIN table2 USING (id)
UNION ALL
SELECT id, false AS flag FROM table1 WHERE id NOT IN (SELECT id FROM table2)
UNION ALL
SELECT id, false AS flag FROM table2 WHERE id NOT IN (SELECT id FROM table1)
ORDER BY id;
UPDATE: I just see that you tagged both MySQL and Amazon Athena. These are two different DBMS. MySQL does not support full outer joins, Athena does. So, for Athena all three queries should work, while for MySQL ony the second and third will.
Try with a UNION:
SELECT
id,
true AS flag
FROM
table2
UNION
SELECT
id,
false AS flag
FROM
table1
WHERE
id NOT IN (
SELECT id FROM table2
)
SELECT
id,
CASE
WHEN id in (SELECT id FROM table2) THEN 'true'
ELSE 'false'
END AS 'flag'
FROM table1
UNION
SELECT
id,
CASE
WHEN EXISTS (SELECT 1 FROM table2) THEN 'true'
ELSE 'false'
END AS 'flag'
FROM table2;
Select
(case when table1.id is null then table2.id else table1.id end) as id,
(case when table2.id is null then false else true end) as flag
from table1 full join table2
on table1.id = table2.id
full join will help get you all ids, in selection you can use case statement to avoid picking nulls in id and flag columns.
You can do it as follows :
select t2.id, 'true' as flag
from table2 t2
union
select id, 'false' as flag
from table1
where id not in ( select id from table2)
Since all ids in table2 must be true, and the others that are not in table2 must be false there is no need of join.
you can try it from here : https://dbfiddle.uk/QIPoFRTb
This is to have them ordered :
select *
from (
select t2.id, 'true' as flag
from table2 t2
union
select id, 'false' as flag
from table1
where id not in ( select id from table2)
) as s
order by id;
For instance,
Select field1
From table1
when table1.field1 = 'S'
then (select field1,2,3,4,5,6,.....
form table1,2,3,4,5,6,....(with joins))
when table1.field1 = 'O'
then (select field1,2,3,4,5,6,.....
from table1,2,3,4,5,6,.....(with join))
I think I got what you need. One possible solution is to create a view with hardcoded where clauses on it. This is the idea:
CREATE VIEW ConditionalSelect AS
SELECT ...fields...
FROM ...tables...
JOIN ...joins...
WHERE table1.field1 = 'S'
AND ....
UNION
SELECT ...fields...
FROM ...tables...
JOIN ...joins...
WHERE table1.field1 = 'O'
AND ....
Then you can do this:
SELECT *
FROM ConditionalSelect
WHERE field1 = 'S'
NOTE: Both SELECT MUST have the same columns, columns types and column names, either the VIEW won't compile.
You could just do something like this:
DECLARE #Field1 VARCHAR(10) =
(
SELECT Field1
FROM table1
);
IF(#Field1 = 'S')
BEGIN
SELECT *
FROM table1 t1
INNER JOIN table2 t2
ON t2.col1 = t1.col1
END
ELSE IF (#Field1 = 'O')
BEGIN
SELECT *
FROM table1 t1
INNER JOIN table2 t2
ON t2.col1 = t1.col1
END
Saves you from creating a view
I'm trying to do something wonky, but I cant think of any other way to do it:
SELECT
my_table.field1 as field1,
(EXISTS (SELECT 1 FROM another_table WHERE id = field1)) as does_exist
FROM my_table
This obviously fails because field1 doesn't exist at the time the result set is created. Does anyone know how to accomplish this?
You can use left join:
select distinct on (t1.field1) t1.field1, t2.id is not null as does_exist
from my_table t1
left join another_table t2 on t2.id = t1.field1
however your query should work as well:
SELECT
my_table.field1 as field1,
(EXISTS (SELECT 1 FROM another_table WHERE id = my_table.field1)) as does_exist
FROM my_table
SELECT
my_table.field1 as field1,
case another_table.ID
when null then 0
else 1
end does_exist
FROM my_table
left outer join another_table on another_table.ID = my_table.field1
Here 1 is Exists, and 0 not exists
Select FieldA, " if data exists in table two return true else false "
from Table1
Left join Table2 on Table1.Id=Table2.Id
This is how I currently do the requirement above:
Select FieldA, (case when Table2.Table2Id is not null then 1 else 0 End)
from Table1
Left join Table2 on Table1.Id=Table2.Id
Is there any replacement for the "Case" statement, to something like ifExists(Table2.Id) ?
You can use EXISTS, i guess you want the strings True/False, otherwise cast 1/0 to bit:
SELECT Id,
DataExists = CASE WHEN EXISTS
(
SELECT 1 FROM Table2 WHERE Table2.Id = Table1.Id
) THEN 'True' ELSE 'False' END
FROM dbo.Table1
For the sake of completeness:
SELECT Id,
DataExists = CAST((CASE WHEN EXISTS
(
SELECT 1 FROM Table2 WHERE Table2.Id = Table1.Id
) THEN 1 ELSE 0 END) AS BIT)
FROM dbo.Table1
May be you can use isNull as well.
Select FieldA, isnull((SELECT 'TRUE' FROM TABLE2 WHERE TABLE2.ID = TABEL1.ID),'FALSE') AS columName
from Table1
I have this table (simplified)
ID | Field1
---------------------------------
2 | Cat
2 | Goat
6 | Cat
6 | Dog
I need to find the IDs where a record exists whose value for field1 is cat and for the same id, another record exists whose value is Goat. In this case, it would only return ID 2.
Doing something like below will not work.
where Field1='Cat' and Field1='Goat'
I'm guessing I need some sort of subquery here? I'm not entirely sure. (Using SQL Server 2008)
Use:
SELECT t.id
FROM YOUR_TABLE t
WHERE t.field1 IN ('Cat', 'Goat')
GROUP BY t.id
HAVING COUNT(DISTINCT t.field1) = 2
The key here is using COUNT (DISTINCT ...) to get a count of the field1 values. Doesn't matter if a user has Cat 3x, and dog 1x... unless you need to filter those out?
Another option is INTERSECT, which returns any distinct values that are returned by both the query on the left and right sides of the INTERSECT operand:
SELECT a.id
FROM YOUR_TABLE a
WHERE a.field1 = 'Cat'
INTERSECT
SELECT b.id
FROM YOUR_TABLE b
WHERE b.field1 = 'Goat'
Try this:
SELECT id FROM
(
SELECT id FROM <YOUR_TABLE> WHERE Field1 = 'Cat'
INTERSECT
SELECT id FROM <YOUR_TABLE> WHERE Field1 = 'Goat'
) a
Alternative:
SELECT a.ID
FROM <YOUR_TABLE> a INNER JOIN <YOUR_TABLE> b
ON a.ID = b.ID
WHERE a.Field1 = 'CAT'
AND b.Field1 = 'GOAT'
Use a query like this
SELECT ID FROM table INNER JOIN
(SELECT ID, COUNT(FILED1) AS Expr1
FROM table GROUP BY ID
HAVING COUNT(FIELD1) > 1) SR ON table.ID = SR.ID WHERE table.FIELD1 = 'Cat'
So you just have to put a variable with a DECLARE for the 'Cat' if you want to have a more dynamic query
SELECT DISTINCT t1.ID
FROM table t1, table t2
WHERE t1.ID=t2.ID AND t1.Field1 <> t2.Field1
Not tested but something like this might work
select t1.ID from tbl t1 inner join tbl t2 on t1.ID=t2.ID
where (t1.Field1='Cat' and t2.Field1='Goat')