I have two table containing one columns in both table
table1
item
table2
item
I want a boolean result true/false if all the values in item column of table1 and table2 are exact match.
e.g columns values for both table
item item
apple apple
boy boy
cat cat
this should return true
item item
apple apple
boy boy
cat dog
should return false
You could check if records exist on one side or the other only by joining the two tables left-to-right and right-to-left. If there are any records not matched, it's false, otherwise true.
select case when exists (
select top 1 1
from Table1 t1
left join Table2 t2 on t2.item = t1.item
where t2.item is null
union all
select top 1 1
from Table2 t2
left join Table1 t1 on t1.item = t2.item
where t1.item is null
)
THEN 'false'
ELSE 'true'
END as result
You can use full join and aggregation:
select (case when count(*) = 0 then 'true' else 'false' end)
from t1 full join
t2
on t1.item = t2.item
where t1.item is null or t2.item is null;
This counts misses. If there are none, then the tables are the same.
Or without the where clause:
select (case when count(t1.item) = count(t2.item) then 'true' else 'false' end)
from t1 full join
t2
on t1.item = t2.item
where t1.item is null or t2.item is null;
Note: Like the data in your question, and the question in general, this assumes that the items are unique.
Related
I have two tables that I want to join.
The case is in table 1 the default value is 1 then in table 2 the default value is 0
Table 1 Table 2
-------- ---------
1 0
1232342 1232342
1241232 1231231
I want to join table 1 and table 2 with condition that if table 2 is 0 then it will be replaced to 1.
SELECT T1.ID
FROM TABLE1 T1, TABLE2 T2
WHERE T1.ID = REPLACE(CASE WHEN T2 = 0 THEN 1 ELSE T2.ID END, 'X', 'E')
with this statement it does not return the other id's that are not 0 or 1
expected output
Table 1
--------
1
1232342
Use a join with a CASE. replace() is for string values:
select t1.*
from table1 t1
join table2 t2 on t1.id = case when t2.id = 0 then 1 else t2.id end;
use case when and sub-query
select t1.* from table1 t1 join
(
select case when t2.id=0 then 1 else t2.id end as id from table2 t2
) as t3 on t1.id=t3.id
Try using case when :
SELECT *
FROM TABLE1 T1 inner join TABLE2 T2
on T1.ID = (CASE WHEN T2.ID =0 THEN 1 ELSE T2.ID END)
Switch to modern, explicit JOIN syntax. Skip the case expression, simply use AND/OR instead:
SELECT T1.ID
FROM TABLE1 T1
JOIN TABLE2 T2
ON T1.ID = T2.ID OR (T1.ID = 1 and T2.ID = 0)
Or use INTERSECT:
SELECT ID FROM TABLE1
INTERSECT
SELECT case when ID = 0 then 1 else id end from TABLE2
In T1 I have a 50 ID'ss. I'm trying to find which ones are in T2. And add row name "test" next to ID with info about occurrence in T2. But when I put my code I receive only ID's which are included in T2. What I`m doing wrong?
SELECT DISTINCT t1.id, CASE WHEN t1.id IS NULL THEN 0 ELSE 1 END AS test
FROM t2
JOIN t1 ON t2.id = t1.id
You can use outer join:
SELECT DISTINCT t1.id, CASE WHEN t2.id IS NULL THEN 0 ELSE 1 END AS test
FROM t1 LEFT JOIN t2 ON t2.id = t1.id
Use exists:
select t1.*,
(case when exists (select 1 from t2 where t2.id = t1.id) then 1 else 0 end) as flag
from t1;
Note that select distinct is not needed. That construct just slows down queries, if it is not needed.
Use Left Join to get the unmatched rows as well.
select t1.id
, case when t2.id is null then 0 else 1 end as test
from t1
left outer join t2
on t1.id = t2.id
I need to combine 3 different columns from 3 tables and result set should be a distinct table.
Attached to the blue table is my question and the yellow table is my expected answer. How Can I Get the expected table?
I don't want duplicates in the name which is column 1.
Any help will be appreciated.
Full Outer Joins
The question doesn't give us much to go on so I am making almost no assumptions about the data. There doesn't seem to be a 'Name' table and none of the 3 tables appears to represent a complete list of names. So, I'm going to close my eyes and type out a couple of full outer joins:
Select t1.name, t1.country, t2.food, t3.movie
from table1 t1
full outer join table2 t2 on t1.name = t2.name
full outer join table3 t3 on t3.name = t1.name
This will give you all of the names (with no assumptions that any one table would need to contain a complete list), each one listed just once (provided they don't already appear multiple times in any one table) along with any data associated with that name from any of the three tables.
Update
So here is an update (see comment below) that replaces the names of the countries, foods, and movies with just 'yes' or 'no'.
Select
t1.name,
case when t1.country is null then 'no' else 'yes' end as country,
case when t2.food is null then 'no' else 'yes' end as food,
case when t3.movie is null then 'no' else 'yes' end as movie
from table1 t1
full outer join table2 t2 on t1.name = t2.name
full outer join table3 t3 on t3.name = t1.name
...and rewritten with generic Column1, Column2 in case that's the issue:
Select
t1.Column1 as name,
case when t1.Column2 is null then 'no' else 'yes' end as country,
case when t2.Column2 is null then 'no' else 'yes' end as food,
case when t3.Column2 is null then 'no' else 'yes' end as movie
from table1 t1
full outer join table2 t2 on t1.Column1 = t2.Column1
full outer join table3 t3 on t3.Column1 = t1.Column1
I hope this helps.
So I came up with an answer to my question.
I used union function to get expected result.
Basically I had 3 tables with one same column name (number).
for instance 700 could be in table 1 and 3 but not in 2 and 701 could be only in table 1.
I used this query:
select Number, SUM(I) as Country, SUM(D) as Place, SUM(A) as City from
(
SELECT distinct(number), CASE WHEN m.number IS NULL THEN 0 ELSE 1 END AS I,0 AS D, 0 AS A
FROM dbo.country M(NOLOCK)
Union
SELECT distinct(number),0 as I,CASE WHEN D IS NULL THEN 0 ELSE 1 END AS D, 0 AS A
FROM dbo.Food F(NOLOCK)
I am currently trying to obtain data from two tables that have the same columns. The values for primary key "ID" of both tables may exist in one or both tables. Even with same primary keys, the values in different columns may not be the same for both tables. My question is given I have an ID testID, how do I query where in I first check table1 if it exists. If it exists in table1 I use the details found in table1, otherwise check table2 and use details in table2 if it exists in table2.
Either use a FULL OUTER JOIN:
select
case when t1.id is not null then t1.field1 else t2.field1 end as field1,
case when t1.id is not null then t1.field2 else t2.field2 end as field2,
...
from table1 t1
full outer join table2 t2 on t2.id = t1.id
where t1.id = :testid or t2.id = :testid;
Or UNION ALL in combination with NOT EXISTS:
select field1, field2, ...
from table1
where id = :testid
union all
select field1, field2, ...
from table2
where id = :testid and not exists (select * from table1 where id = :testid);
The possible way is to use FULL OUTER JOIN
SELECT t1.id,
t2.id,
CASE
WHEN t1.id IS NOT NULL
AND t2.id IS NOT NULL
THEN 'ID in both sources'
WHEN t1.id IS NULL
THEN 'ID in T2 only'
WHEN t2.id IS NULL
THEN 'ID in T1 only'
END source_key
FROM t1
FULL OUTER JOIN t2
ON t1.id = t2.id
WHERE t1.id = 1 -- your test_id here
OR t2.id = 1; -- your test_id here
Cheching if T1.ID/ T2.ID is not NULL you get the information if the record is defined in the respective source table.
A query with left join is not returning records, although the where clause from the left table should find a single record. In this case, it should return a record with the fields from the left table containing values and from the right table null, since there is no match between them.
Apparently there is a problem with the use of case that references the right table on the join expression.
In SQL Server the same query worked as expected.
select
t1.Description, t2.Description
from
A t1
left join
B t2
on
t1.Id = t2.Id and
1 = case when (
t2.Id = t2.Id and
(select t3.Flag from C t3 where t3.ID_B = t2.Id) = 'S'
) then 1 else 0
end
where t1.Id = 1
Result: no rows returned.
Then I moved the expression t2.Id = t2.Id (that is here only to demonstrate the problem and should always return true, apparently) out of the case expression.
select
t1.Description, t2.Description
from
A t1
left join
B t2
on
t1.Id = t2.Id and
t2.Id = t2.Id and
1 = case when (
(select t3.Flag from C t3 where t3.ID_B = t2.Id) = 'S') then 1 else 0
end
where t1.Id = 1
Result: one row returned.
The queries above only serve to demonstrate the problem, are not useful in a real situation and not optimized.
I want to know if anyone knows any limitation of Oracle related to this case. So far we believe it is a bug.
Data used:
A: Id=1, Description=Item A1;
B: Id=1, Description=Item B1;
C: Id=1, Id_B=2, Flag=S.
CREATE TABLE t1 AS (SELECT 1 ID FROM dual);
CREATE TABLE t2 AS (SELECT 2 ID FROM dual);
CREATE TABLE t3 AS (SELECT 2 id_b, 's' flag FROM dual);
SELECT t1.*
FROM t1 LEFT JOIN t2
ON t1.ID = t2.ID
AND 1 = CASE WHEN t2.id = t2.id and (SELECT flag FROM t3 WHERE t3.id_b = t2.ID) = 's' THEN 1 ELSE 0 END
where t1.id = 1;
The output: no rows selected
The result looks strange, I suppose it can be a bug.
Oracle documentation only states
https://docs.oracle.com/cd/B28359_01/server.111/b28286/queries006.htm#SQLRF52337
You cannot compare a column with a subquery in the WHERE clause of any
outer join, regardless which form you specify.
By looking on the plan of the above query I can see that this condition:
AND 1 = CASE WHEN t2.id = t2.id and (SELECT flag FROM t3 WHERE t3.id_b = t2.ID) = 's' THEN 1 ELSE 0 END
Is interpreted as:
CASE WHEN (T2.ID(+)=T2.ID(+) AND (SELECT FLAG FROM T3 T3 WHERE T3.ID_B=:B1)='s') THEN 1 ELSE 0 END =1
and is calculated after the join.
I suppose that Oracle cannot calcuate the CASE until the join is performed (because of T2.ID(+)=T2.ID(+))
Your assumption that t2.id = t2.id is always true is wrong. If the value were NULL that would be treated as false. I don't believe that is relevant for this particular example, but just to clarify.
The question is how is a left join processed. The idea is simple. The on clause is processed. If there are no matches, then the row from the first table is kept. This is regardless of what is in the on clause. (This is a functional description; there are many possible implementations.)
Based on your sample data, Oracle is incorrect. One row should be returned. The SQL Server example should also return one row. I suspect that the data might be subtly different; I personally have never had issues with left joins in SQL Server (or Oracle).
Using SQLFiddle Oracle 11g R2 (thanks to Shannon Severance) your first query gives Record Count: 0 but by simply removing the CASE we get Record Count: 1. (Note the renaming of t2Description.)
create table A (ID number(38), Description varchar(10));
create table B (ID number(38), Description varchar(10));
create table C (ID number(38), ID_B number(38), Flag varchar(10));
insert into A values(1, 'Item A1');
insert into B values(2, 'Item B1');
insert into C values(1, 2, 'S');
select
t1.Description, t2.Description as t2d
from
A t1
left join
B t2
on
t1.Id = t2.Id and
t2.Id = t2.Id and
(select t3.Flag from C t3 where t3.ID_B = t2.Id) = 'S'
where t1.Id = 1
This suggests that it has something to do with CASE being miscalculated.
Note that in the ON t2.Id is at least sometimes (correctly) taken to be the value from the FROM cross product, not NULL which it is after the ON:
select
t1.Description, t2.Description as t2d
from
A t1
left join
B t2
on
-- for above data t2.id should be 1 here
t2.id is null
where t1.Id = 1
-- for above data t2.id should be null here
DESCRIPTION T2D
Item A1 (null)
I found this link: Outer Join Bug in Oracle 12c?