So, I would like the next query for postgres:
SELECT name
FROM Table1 as T1
WHERE T1.id = (
SELECT id
FROM Table2 AS T2
WHERE T2.active=true)
So, I need to get all the values from the first table, whose id matches the ones set as active in another table.
You don't need a sub query for this. Use a join. It will be a lot more efficient.
SELECT T1.name
FROM Table1 as T1
INNER JOIN Table2 as T2 ON T2.id = T1.id AND T2.active=true
The equality operator imposes that the subquery should return a single record. You want IN instead, which accepts a resultset:
SELECT T1.name
FROM Table1 as T1
WHERE T1.id IN (SELECT id FROM Table2 AS T2 WHERE T2.active)
This can also be expressed with EXISTS:
SELECT T1.name
FROM Table1 as T1
WHERE EXISTS (SELECT 1 FROM Table2 AS T2 WHERE T2.id = T1.id AND T2.active)
Note that in Postgres condition T2.active = true can be shortened T2.active.
For performance, you want an index on Table2(id, active) and another on Table1(id).
Related
I have two differents tables. The have some columns in common, for this example lets say 'name' and 'id'.
By making
( SELECT name,id FROM table1
EXCEPT
SELECT name,id FROM table2)
UNION ALL
( SELECT name,id FROM table2
EXCEPT
SELECT name,id FROM table1)
I get a list of the elements that are on one tablet but not in the other one.
Up to this point everything is OK.
But now, I want to make a select all from table1 where the name and the id matches the result of the query above.
After lots of comments I think this is what you're after...
SELECT T1.*
FROM table1 t1
LEFT JOIN table2 t2
on T1.ID = T2.ID
and T1.Name = T2.Name
AND E2.event_Time_UTC between convert(datetime,'2016-02-09 00:00:20',101) and convert(datetime '2016-02-09 23:59:52',101)
WHERE T2.Name is null
AND E1.Event_Time_UTC between convert(datetime,'2016-02-09 00:00:20',101) and convert(datetime,'2016-02-09 23:59:52',101)
You may allow implicit casting to work but above is the explicit approach.
If not then you would need to cast the string dates to a date time, assuming Event_Time_UTC is a date/time datatype.
A left join lets us return all records from the 1st table and only those that match from the 2nd.
The t1.* returns only the columns from table1. The join criteria (on) allows us to identify those records which match so they can then be eliminated in the where clause by 'where t2.name is null' they will always be null when no record match in t2.
Thus you get a result set that is: all records from t1 without a matching record on name and id in table2.
Old version
The below content is no longer relevant, based on comments.
I redacted previous answer a lot because you're using SQL Server not MySQL and I know you want multiple records not table1 and table2 joined.
In the below I create two tables: table1 and table2. I then populate table1 and table2 with some sample data
I then show how to get only those records which exist in one table but not the other; returning a separate ROW for each. I then go into detail as to why I choose this approach vs others. I'll finally review what you've tried and try to explain why I don't think it will work.
create table table1 (
ID int,
name varchar(20),
col1 varchar(20),
col2 varchar(20),
col3 varchar(20));
Create table table2 (
id int,
name varchar(20));
Insert into table1 values (1,'John','col1','col2','col3');
Insert into table1 values (2,'Paul','col1','col2','col3');
Insert into table1 values (3,'George','col1','col2','col3');
Insert into table2 values (1,'John');
Insert into table2 values (4,'Ringo');
Option 1
SELECT T1.name, T1.ID, T1.Col1, T1.Col2, T1.Col3
FROM Table1 T1
LEFT JOIN Table2 T2
on T1.Name = T2.Name
and T1.ID = T2.ID
WHERE T2.ID is null
UNION ALL
SELECT T2.name, T2.ID, NULL, NULL, NULL
FROM Table1 T1
RIGHT JOIN Table2 T2
on T1.Name = T2.Name
and T1.ID = T2.ID
WHERE T1.ID is null ;
which results in...
Notice John isn't there as it's in both tables. We have the other 2 records from table1, and the ID, name from table2 you're after.
Normally I would do this as a full outer join but since I think you want to reuse the name and id fields to relate to BOTH tables in the same column we had to use this approach and spell out all the column names in table 1 and put NULL for each column in table1 when displaying records from table2 in order to make the output of the second query union to the first. We simply can't use *
Option 2: Using a full outer join... with all columns from T1
SELECT T1.*
FROM Table1 T1
FULL OUTER JOIN Table2 T2
on T1.ID = T2.ID
and T1.Name = T2.Name
WHERE (T1.ID is null or T2.ID is null)
you get this... which doesn't show Ringo...
But then I would ask why you need anything from Table 2 at all so I think you're wanting to still show the ID, Name from table2 when it doesn't exist in table1.
Which is why What I think you're after is the results from the 1st query using the union all.
Option 3 I suppose we could avoid the second query in option 1 by doing...
SELECT coalesce(T1.Name, T2.name) as name, coalesce(T1.Id,T2.ID) as ID, T1.col1, T1.Col2, T1.Col3
FROM Table1 T1
FULL OUTER JOIN Table2 T2
on T1.ID = T2.ID
and T1.Name = T2.Name
WHERE (T1.ID is null or T2.ID is null)
which gives us what I believe to be the desired results as well.
This works because we know we only want the name,id from table2 and all the column values in table1 will be blank.
Notice however in all cases we simply can't use Tablename.* to select all records from table1.
This is what you tried:
( SELECT name,id FROM table1
EXCEPT
SELECT name,id FROM table2)
UNION ALL
( SELECT name,id FROM table2
EXCEPT
SELECT name,id FROM table1)
Assuming you want to reuse the ID, Name fields; you can't select *. Why? because the records in Table2 not in table1 aren't in table1. In my example if you want Ringo to show up you have to reference table2! Additionally, * gives you no ability to "Coalesce" the ID and name fields together as I did in option 3 above.
If you ONLY want the columns from table1, that means you will NEVER see data from table2. If you don't need the data from table2, (such as ringo in my example) then why do we need to do the union at all?) I'm assuming you want ringo, thus you HAVE to somewhere reference name, id from table2.
You could also do this with NOT EXISTS:
SELECT *
FROM table1
WHERE
NOT EXISTS
(SELECT 1
FROM table2
WHERE table1.id = table2.id
AND table1.name = table2.name)
;with cte as
(
( SELECT name,id FROM table1
EXCEPT
SELECT name,id FROM table2)
UNION ALL
( SELECT name,id FROM table2
EXCEPT
SELECT name,id FROM table1)
)
Select *
from table1 as tbl1
where
tbl1.id = cte.id
and tbl1.name = cte.name
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.
I have a SQL Insert statement that needs to insert records into another table only if the the record doesn't exist in table2 or the zip code has changes in table1. I have tried the following but it throws an error and it is the logic I am looking for:
INSERT INTO table2
SELECT id, zip
FROM table1 t1
JOIN table2 t2
ON t1.id = t2.id and t1.zip <> t2.zip
I also need it to insert the records if the id doesn't exist at all in table2. I have googled the crap out of this and can't seem to find the solution anywhere.
What about this?
INSERT INTO table2
SELECT t2.id, t2.zip
FROM table1 t1
LEFT OUTER JOIN table2 t2
ON t1.id = t2.id
WHERE (t1.id IS NULL OR t2.zip <> t1.zip)
Also, be sure to clarify which table's id and zip columns you are asking for.
You should always include column lists when doing inserts. Second, your query doesn't quite capture your logic. You need a left outer join to find the records that don't exist in the second table. Perhaps this might do what you want:
INSERT INTO table2(id, zip)
SELECT id, zip
FROM table1 t1 LEFT JOIN
table2 t2
ON t1.id = t2.id
WHERE (t1.zip <> t2.zip) or (t2.zip is null)
You just need a WHERE NOT EXISTS clause
INSERT INTO table2
SELECT id, zip
FROM table1
WHERE NOT EXISTS (SELECT 1 FROM table2 WHERE table2.id = table1.id AND table2.zip = table1.zip)
Is there a quicker way to get the ids that exist in table1 but not exist in table2 and insert them in table2?
insert into table2 (id)
select id
from table1
where table1.id not in (select id from table2)
In addition to your solution using the in operator try the exists one
select id
from table1 t1
where not exists (
select 1
from table2
where id = t1.id
)
If the subquery returns an empty set not exists evaluates to true
The outer join
select id
from
table1 t1
left join
table2 t2 on t1.id = t2.id
where t2.id is null
Use explain analyze to compare
I need to run a query where one of the fields returned is a yes or no if there is a row in another table matching one of the key fields in the first table.
Sounds like a job for join, except the second table is one to many and I just need to know if there are zero or a non zero number of rows in the secondary table.
I could do something like this:
select t1.name, t1.id, (select count(1) from t2 where t1.id=t2.id) from t1
but I'd like to avoid making an aggregate subquery if possible.
It was mentioned to me that I could use the exists() function, but I'm not seeing how to do that in a select field.
This is sybase 15 by the way.
You could still do the JOIN, something like this:
SELECT t1.name, t1.id, CASE WHEN t2.id IS NULL THEN 0 ELSE 1 END Existst2
FROM t1
LEFT JOIN (SELECT id FROM t2 GROUP BY id) t2
ON t1.id = t2.id
ahhh, I got it from another stackoverflow quetion...
case when exists (select * from t2 where t1.id = t2.id) then 1 else 0 end
I am just writing down the syntax here:
if exists (select * from table1 t1 inner join table1 t2 on t1.id = t2.id )
select * from table2
How about this query ( Work with all databases )
select t1.name, t1.id, 'Y' as HasChild
from t1
where exists ( select 1 from t2 where t2.id = t1.id)
UNION
select t1.name, t1.id, 'N' as HasChild
from t1
where NOT exists ( select 1 from t2 where t2.id = t1.id)