In SQL, how can I perform a "subtraction" operation? - sql

Suppose I have two tables, which both have user ids. I want to perform an operation that would return all user IDS in table 1 that are not in table 2. I know there has to be some easy way to do this - can anyone offer some assistance?

Its slow, but you can normally accomplish this with something like 'not in'. (There are other functions in various RDBMS systems to do this in better ways, Oracle for instance has a 'exists' clause that can be used for this.
But you could say:
select id from table1 where id not in (select id from table2)

There are a few ways to do it. Here's one approach using NOT EXISTS:
SELECT userid
FROM table1
WHERE NOT EXISTS
(
SELECT *
FROM table2
WHERE table1.userid = table2.userid
)
And here's another approach using a join:
SELECT table1.userid
FROM table1
LEFT JOIN table2
ON table1.userid = table2.userid
WHERE table2.userid IS NULL
The fastest approach depends on the database.

One way is to use EXCEPT if your TSQL dialect supports it. It is equivalent to performing a left join and null test

SELECT user_id FROM table1 LEFT JOIN table2 ON table1.user_id = table2.user_id WHERE table2.user_id IS NULL;

If it is
SQL Server:
SELECT id FROM table1
EXCEPT
SELECT id FROM table2
Oracle:
SELECT id FROM table1
MINUS
SELECT id FROM table2
Rest: Am not sure....

Try this:
SELECT id FROM table1 WHERE id NOT IN
(
SELECT id FROM table2
)

select ID from table1
where ID not in (select ID from table2)

Related

Pass values as parameter from select query

I want to pass values from output of select query to another query. Basically both queries will be part of a stored procedure. e.g.
select Id, RelId
from tables
There will be multiple rows returned by above query and I want to pass them to the following query
select name
from table2
where Id = #Id and MgId = #RelId
Please suggest
You cannot pass multiple values in SQL.
But maybe you can just join your 2 tables, that would be far more efficient.
Not knowing your table schemes I suggest something like this. You might have to adapt this to your actual table schemas off course
select name
from table2 t2
inner join tables t on t2.Id = t.Id
and t2.MgId = t.RelId
EDIT
As Gordon mentioned in his answer, this approach can show double rows in your result.
If you don't want that than here are 2 ways of getting rid of the doubles
select distinct name
from ...
or by grouping by adding this at the end of the statement
group by name
Though this will work, avoiding the doubles like in Gordon's answer is better
I would suggest using exists:
select t2.name
from table2 t2
where exists (select 1
from tables t
where t2.Id = t.Id and t2.MgId = t.RelId
);
The difference between exists and join is that this will not generate duplicates, if there are multiple matches between the tables.
Or...
SELECT *
INTO #Table1
FROM ...
SELECT *
INTO #Table2
FROM ...
SELECT *
FROM #Table1 T1
JOIN #Table2 T2
DROP TABLE #Table1, #Table2

SQL IN operator value of subquery

I want to get a value from an IN subquery with two columns, without needing to do two queries.
Sample:
SELECT * FROM table1 WHERE id IN(SELECT id, flags FROM table2);
Now I want to get flags directly. Is it possible, and if yes, how?
Any help is appreciated :)
It sounds like you are trying to achieve one of two things:
1) Select every field of records in table1 (and the associated table 2 flag) where the record's id is also found in the id column of table2. If that is the case, then yes, a join will accomplish what you want:
SELECT t1.*,
t2.flags
FROM table1 t1
JOIN table2 t2
ON t1.id = t2.id;
Note that JOIN is used here (rather than other types of joins such as LEFT JOIN) because JOIN will return only table1 records with a match in table2.id. LEFT JOIN, on the other hand, would return every table1 record, and table1 ids without a match in table2 would simply have null in the flags column of your returned table.
2) Select every field of records in table1 where the record's id is also found in either the id column of table2 or the flags column of table2. If that is the case, there are a few ways you could get the desired result, but achieving this using a subquery similar to the question
SELECT *
FROM table1
WHERE id IN (SELECT id FROM table2 UNION DISTINCT SELECT flags FROM table2)
You do this using join:
SELECT t1.*, t2.flags
FROM table1 t1 JOIN
table2 t2
ON t1.id = t2.id;

How to make Query with IN in WHERE clause run faster

I have this query in Oracle11g :
SELECT DOC_ID,DOC_NAME,DESC
FROM TABLE1
WHERE DOC_ID NOT IN(
SELECT DOC_ID FROM TABLE2
)
The sql query above run very slow since i have so many data in the tables.
Is there any solution to get the same result with better performance and run faster?
Any help much appreciated.
Thanks.
Using WHERE EXISTS may have better performance:
SELECT DOC_ID,DOC_NAME,DESCr
FROM TABLE1 t1
WHERE not exists (
SELECT 1 FROM TABLE2 where
doc_id = t1.doc_id
);
Example: http://sqlfiddle.com/#!4/4b59e/3
I wouldn't use the in statement for that. If you join on what I imagine is one of your keys it should be much much faster:
select tb1.DOC_ID, tb1.DOC_NAME, tb1.DESC
from table1 tb1
left join table2 tb2
on tb1.DOC_ID = tb2.DOC_ID
where tab2.DOC_ID is not null

How to insert all rows from one table in the column in () statement in Hive

I have a table with 100 strings that I would like to add to a where column in (value, value, etc) Something like select cookies from table where field in (select * from table)
I don't think Hive supports subqueries in in clauses, but you can accomplish the same with an inner join:
select table1.cookies
from table1 join table2 on table1.field = table2.field
Hive does have a support of SUB-QUERIES from version-0.13.
So you can use this version.
Or you can try this query:
select * from table1 t1 JOIN (select 100_string_column as col2 from table2 where (whatever your condition is)) t2 ON t1.<matching_column> = t2.col2
Hope this helps...!!!

Is it possible to restrict the results of an outer join?

I've got a scenario where I need to do a join across three tables.
table #1 is a list of users
table #2 contains users who have trait A
table #3 contains users who have trait B
If I want to find all the users who have trait A or trait B (in one simple sql) I think I'm stuck.
If I do a regular join, the people who don't have trait A won't show up in the result set to see if they have trait B (and vice versa).
But if I do an outer join from table 1 to tables 2 and 3, I get all the rows in table 1 regardless of the rest of my where clause specifying a requirement against tables 2 or 3.
Before you come up with multiple sqls and temp tables and whatnot, this program is far more complex, this is just the simple case. It dynamically creates the sql based on lots of external factors, so I'm trying to make it work in one sql.
I expect there are combinations of in or exists that will work, but I was hoping for some thing simple.
But basically the outer join will always yield all results from table 1, yes?
SELECT *
FROM table1
LEFT OUTER
JOIN table2
ON ...
LEFT OUTER
JOIN table3
ON ...
WHERE NOT (table2.pk IS NULL AND table3.pk IS NULL)
or if you want to be sneaky:
WHERE COALESCE(table2.pk, table3.pk) IS NOT NULL
but for you case, i simply suggest:
SELECT *
FROM table1
WHERE table1.pk IN (SELECT fk FROM table2)
OR table1.pk IN (SELECT fk FROM table3)
or the possibly more efficient:
SELECT *
FROM table1
WHERE table1.pk IN (SELECT fk FROM table2 UNION (SELECT fk FROM table3)
If you really just want the list of users that have one trait or the other, then:
SELECT userid FROM users
WHERE userid IN (SELECT userid FROM trait_a UNION SELECT userid FROM trait_b)
Regarding outerjoin specifically, longneck's answer looks like what I was in the midst of writing.
I think you could do a UNION here.
May I suggest:
SELECT columnList FROM Table1 WHERE UserID IN (SELECT UserID FROM Table2)
UNION
SELECT columnList FROM Table1 WHERE UserID IN (SELECT UserID FROM Table3)
Would something like this work? Keep in mind depending on the size of the tables left outer joins can be very expensive with regards to performance.
Select *
from table1
where userid in (Select t.userid
From table1 t
left outer join table2 t2 on t1.userid=t2.userid and t2.AttributeA is not null
left outer join table3 t3 on t1.userid=t3.userid and t3.AttributeB is not null
group by t.userid)
If all you want is the ids of the users then
SELECT UserId From Table2
UNION
SELECT UserId From Table3
is totally sufficient.
If you want some more infos from Table1 on these users, you can join the upper SQL to Table 1:
SELECT <list of columns from Table1>
FROM Table1 Join (
SELECT UserId From Table2
UNION
SELECT UserId From Table3) User on Table1.UserID = Users.UserID