How make a union of two columns with different value of fields - sql

I Have two columns from different selects in sql server
Table 1
ID Name Bit
.... ............ .....
1 Enterprise 1 False
2 Enterprise 2 True
3 Enterprise 3 False
Table 2
ID Name Bit
.... ............ .......
1 Enterprise 1 True
2 Enterprise 2 False
3 Enterprise 3 False
expected result
ID Name Bit
.... ............ ......
1 Enterprise 1 True
2 Enterprise 2 True
3 Enterprise 3 False
the problem is make a union between the two tables and the bit column prevail fields that are true
Any ideas?

I would suggest casting it to an int:
select id, name, cast(max(bitint) as bit) as bit
from ((select id, name, cast(bit as int) as bitint
from table1
) union all
(select id, name, cast(bit as int) as bitint
from table2
)
) t12
group by id, name;
With your data, you can also do it using join:
select t1.id, t1.name, (t1.bit | t2.bit) as bit
from table1 t1 join
table2 t2
on t1.id = t2.id and t1.name = t2.name;
This assumes all the rows match between the two tables (as in your sample data). You can do something similar with a full outer join if they don't.

You can make a left join on the other table to exclude the records that should be used from the other table:
select
t1.ID, t1.Name, t1.Bit
from
[Table 1] t1
left join [Table 2] t2 on t2.ID = t1.ID
where
t1.Bit = 1 or t2.Bit = 0
union all
select
t2.ID, t2.Name, t2.Bit
from
[Table 2] t2
left join [Table 1] t1 on t1.ID = t2.ID
where
t1.bit = 0 and t2.Bit = 1
(If there is a True in both tables or a False in both tables for an item, the record from Table 1 is used.)

SELECT Table1.ID, Table1.Name, IIF(Table1.[Bit]>0 OR Table2.[Bit]>0,1,0) AS [Bit]
FROM
(VALUES(1,'Enterprise 1',0),(2,'Enterprise 2',1),(3,'Enterprise 3',0)) as Table1(ID,Name,Bit),
(VALUES(1,'Enterprise 1',1),(2,'Enterprise 2',0),(3,'Enterprise 3',0)) as Table2(ID,Name,Bit)
WHERE Table1.ID = Table2.ID
It seems to me that you are just doing a logical OR operation on the Bit column and calling it UNION.

Related

Join 2 tables in SQL and create a flag column based on a match

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;

How to create table with binary values based on existing some values in two other tables in Teradata SQL?

I have two tables in Teradata SQL like below:
Table1:
ID
10
11
12
Table2:
ID
10
13
14
15
Based on two tables above I need to create one table like below.
So:
col: tab1 --> If ID is in table 1 give them 1 and 0 otherwise.
col: tab2 --> If ID is in table 2 give them 1 and 0 otherwise.
Desired result:
ID
tab1
tab2
10
1
1
11
1
0
12
1
0
13
0
1
14
0
1
15
0
1
How can I do that in Teradata SQL ?
Teradata seems to support enough of ISO SQL-2003 natively, so no Teradata-specific SQL extensions or proprietary features is needed (i.e. the exact same query will work in MSSQL Server, Oracle, MariaDB, etc).
You'll want a UNION of table1 and table2's values and then JOINed back, which is straightforward:
WITH distinctIdValues AS (
SELECT id FROM table1
UNION
SELECT id FROM table2
)
SELECT
dv.id,
CASE WHEN t1.id IS NOT NULL THEN 1 ELSE 0 END AS tab1,
CASE WHEN t2.id IS NOT NULL THEN 1 ELSE 0 END AS tab2
FROM
distinctIdValues AS dv
LEFT OUTER JOIN table1 AS t1 ON dv.id = t1.id
LEFT OUTER JOIN table2 AS t2 ON dv.id = t2.id
You can then use this query either as a VIEW or materialize it into a new TABLE:
CREATE VIEW foobar AS /* same SQL as above */;
SELECT * FROM foobar;
Teradata's documentation is unclear about how/if a CTE can be used with an INSERT statement, so I'll use an inner-query instead:
CREATE TABLE foobar (
id int NOT NULL PRIMARY KEY,
tab1 byteint NOT NULL,
tab2 byteint NOT NULL
);
INSERT INTO foobar ( id, tab1, tab2 )
SELECT
dv.id,
CASE WHEN t1.id IS NOT NULL THEN 1 ELSE 0 END AS tab1,
CASE WHEN t2.id IS NOT NULL THEN 1 ELSE 0 END AS tab2
FROM
(
SELECT id FROM table1
UNION
SELECT id FROM table2
)
AS dv
LEFT OUTER JOIN table1 AS t1 ON dv.id = t1.id
LEFT OUTER JOIN table2 AS t2 ON dv.id = t2.id
ORDER BY
dv.id
;
Or just this:
Props to #dnoeth for reminding me that it can be reduced to this:
SELECT
COALESCE( t1.id, t2.id ) AS id,
CASE WHEN t1.id IS NULL THEN 0 ELSE 1 END AS tab1,
CASE WHEN t2.id IS NULL THEN 0 ELSE 1 END AS tab2
FROM
table1 AS t1
FULL OUTER JOIN table2 AS t2 ON t1.id = t2.id
ORDER BY
COALESCE( t1.id, t2.id )
You just need a Full Outer Join:
SELECT
Coalesce(t1.id, t2.id) AS id
,CASE WHEN t1.id IS NULL THEN 0 ELSE 1 END AS tab1
,CASE WHEN t2.id IS NULL THEN 0 ELSE 1 END AS tab2
FROM table1 AS t1
FULL JOIN table2 AS t2
ON t1.id = t1.id

SQL Get Count Across 3 Tables

I have a 3 tables, one with these two columns
table1:
id, name
0 foo
1 etc
2 example
table2:
id table1_id
0 1
1 0
2 2
table3:
id table2_id
0 1
1 0
2 0
Which query can I find all 'name's from table1 where ALL ids in table2 have a count of atleast n in table3? i.e if n was 1 it should return foo and etc
EDIT:
Explained poorly, I'm trying to get the name of every record in table1 where ALL corresponding records in table2 (i.e records where the column table1_ID is equal to each id within table1. In my example tables, each ID has one) have a count in table3 of atleast n.
If n was 1, as the table2_id 0 appears twice in records 1 and 2, its 'parent' would be returned. It corresponds to the table 1 record 1, so the name of the record with table1 id: 1 should be returned, which is etc. Example also as it has a count of 1 in the bottom column, however foo does not appear so it shouldnt.
Expected result:
name
foo
etc
You can do this using a subquery in the where clause:
select t1.*
from table1 t1
where (select count(t3.id)
from table2 t2 left join
table3 t3
on t3.table2_id = t2.id
where t2.table1_id = t1.id
group by t2.id
order by count(*) asc -- to get the minimum
limit 1
) >= ? -- value you care about
I suspect that this might have the best performance with appropriate indexes: table2(table1_id, id) and table3(table2_id).
If I have understood the question - if a check on table3.table2_id is greater than 0, the answer would be 'etc' ?
Code below
select t1.name
from
(
select 0 as id, 1 as table2_id
union select 1, 0
union select 2 , 0
) t3
inner join
(
select 0 as id , 1 as table_id
union select 1, 0
union select 2, 2
) t2 on t2.table_id = t3.table2_id
inner join
(
select 0 as id, 'foo' as name
union select 1 , 'etc'
union select 2 , 'example'
) t1 on t1.id = t2.table_id
where t3.table2_id > 0
select table1.name
FROM table1
INNER JOIN table2 ON table1.id=table2.table1_id
INNER JOIN table3 ON table2.id=table3.table2_id
GROUP BY table1.name
HAVING count(*) >= 1
replace the last 1 with whatever n you desire
Here's the sql fiddle if you want to play around with it: http://sqlfiddle.com/#!7/14217/4
Use an INNER join of table1 to table2 and then a LEFT join to table3 and count the corresponding ids of table3.
Then by a 2nd level of aggregation return only the rows of table1 where all the counters are at least 1:
SELECT id, name
FROM (
SELECT t1.id, t1.name, COUNT(t3.id) counter
FROM table1 t1
INNER JOIN table2 t2 ON t2.table1_id = t1.id
LEFT JOIN table3 t3 ON t3.table2_id = t2.id
GROUP BY t1.id, t1.name, t2.id
)
GROUP BY id, name
HAVING MIN(counter) >= 1 -- change to the number that you want
See the demo.
Results:
id
name
0
foo
1
etc

Oracle Sql - I have two tables and need to filter table1 with results from table2. I need to return all of table1 if table2 is empty

I'm currently turning a comma-separated string into a number table with the field name of ID. I'm then trying to do an nvl to select all if the generated table is null.
table1.ID = NVL(table2.ID, table1.ID)
I have two tables and need to filter table1 with results from table2. I need to return all of table1 if table2 is empty.
Scenario I
Table1
ID
1
2
3
4
Table2 (Empty)
ID
Return rows 1, 2, 3, 4
Scenario II
Table1
ID
1
2
3
4
Table2
ID
2
3
Return rows 2, 3
You can use filtering in the where clause:
select t1.id
from table1 t1
where not exists (select 1 from table2) or
exists (select 1 from table2 t2 where t2.id = t1.id);
I don't think join is the right way to express this logic.
You can also use UNION
select t1.id
from table1 t1
where not exists (select 1 from table2 where id = t1.id) union all
select t2.id
from table2 t2
where exist (select 1 from table1 where id = t2.id);

Tsql select from related table with AND condition

I've two related tables:
Table1
Id
-----
1
2
3
Table2
Id Feature
--------------
1 Car
1 Moto
1 Camper
2 Moto
2 Scooter
3 Apple
I want to select Ids which have, for example, both 'Car' AND 'Moto'.
So in the example i want to get only Id = 1.
Use the INTERSECT operator:
select id from table2 where feature = 'Car'
intersect
select id from table2 where feature = 'Moto'
This:
WITH features AS
(
SELECT feature
FROM (
VALUES
('Car'),
('Moto')
) q (feature)
)
SELECT *
FROM table1 t1
WHERE NOT EXISTS
(
SELECT feature
FROM features
EXCEPT
SELECT feature
FROM table2 t2
WHERE t2.id = t1.id
)
or this:
SELECT *
FROM table t1
WHERE (
SELECT COUNT(*)
FROM table2 t2
WHERE t2.id = t1.id
AND t2.feature IN ('Car', 'Moto')
) = 2
Which query is more efficient depends on how many records you have in both tables and how many matches there are.
This select does two LEFT OUTER JOINs to table2 (one based on 'Car' and the other based on 'Moto') and makes sure that each JOIN returned a result. The DISTINCT ensures that you get each ID only once.
SELECT DISTINCT t1.id
FROM table2 t2
LEFT OUTER JOIN table2 t2_2 ON t2.id = t2_2.id AND t2_2.feature = 'Moto'
WHERE t2.feature = 'Car'
AND t2_2.id IS NOT NULL
Edit: Removed join to table1 since it really isn't needed.