SQL Query Help - sql

Duplicate:
How to do a Select in a Select
I have 2 tables:
TABLE1
Table1Id
TABLE2
Table2Id
Table1Id
UserId
TABLE2 has thousands of entries in it. I want to return a list of TABLE1 entries where there isn't an entry in TABLE2 for it for a particular user. So, where there isn't a foreign key entry in TABLE2. A query like:
select count(*) from TABLE1 where Table1Id not in (
select Table1Id from TABLE2 where id_user = 1)
However, that query runs very slowly. What would be the most efficient way of getting the results I require?

There is a similar question
I think it would be better
SELECT COUNT(*)
FROM TABLE1
WHERE NOT EXISTS (SELECT Table1Id FROM TABLE2 WHERE TABLE2.Table1Id = TABLE1.Table1Id AND UserID = 1)
I would check the indexes also, as ck suggested

What about
select Table1Id from TABLE1
minus
select Table1Id from TABLE2 where id_user = 1
I am not sure, it MsSql support minus. If not, you should try a correlated subquery.

You can also use the 'EXCEPT/MINUS' intersect to get only differences between the two tables as long as the selection returns the same field types/order.
SELECT TABLE1ID
FROM TABLE1
EXCEPT -- or MINUS in Oracle
SELECT TABLE1ID
FROM TABLE2
WHERE USER_ID = 1

See How to do a Select in a Select
Also, make sure that any fields you are querying have a suitable index.

Related

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;

Simple update statement so that all rows are assigned a different value

I'm trying to set a column in one table to a random foreign key for testing purposes.
I attempted using the below query
update table1 set table2Id = (select top 1 table2Id from table2 order by NEWID())
This will get one table2Id at random and assign it as the foreign key in table1 for each row.
It's almost what I want, but I want each row to get a different table2Id value.
I could do this by looping through the rows in table1, but I know there's a more concise way of doing it.
On some test table my end your original plan looks as follows.
It just calculates the result once and caches it in a sppol then replays that result. You could try the following so that SQL Server sees the subquery as correlated and in need of re-evaluating for each outer row.
UPDATE table1
SET table2Id = (SELECT TOP 1 table2Id
FROM table2
ORDER BY Newid(),
table1.table1Id)
For me that gives this plan without the spool.
It is important to correlate on a unique field from table1 however so that even if a spool is added it must always be rebound rather than rewound (replaying the last result) as the correlation value will be different for each row.
If the tables are large this will be slow as work required is a product of the two table's rows (for each row in table1 it needs to do a full scan of table2)
I'm having another go at answering this, since my first answer was incomplete.
As there is no other way to join the two tables until you assign the table2_id you can use row_number to give a temporary key to both table1 and table2.
with
t1 as (
select row_number() over (order by table1_id) as row, table1_id
from table1 )
,
t2 as (
select row_number() over (order by NEWID()) as row, table2_id
from table2 )
update table1
set table2_id = t2.table2_id
from t1 inner join t2
on t1.row = t2.row
select * from table1
SQL Fiddle to test it out: http://sqlfiddle.com/#!6/bf414/12
Broke down and used a loop for it. This worked, although it was very slow.
Select *
Into #Temp
From table1
Declare #Id int
While (Select Count(*) From #Temp) > 0
Begin
Select Top 1 #Id = table1Id From #Temp
update table1 set table2Id = (select top 1 table2Id from table2 order by NEWID()) where table1Id = #Id
Delete #Temp Where table1Id = #Id
End
drop table #Temp
I'm going to assume MS SQL based on top 1:
update table1
set table2Id =
(select top 1 table2Id from table2 tablesample(1 percent))
(sorry, not tested)

SQL selecting records from one table and using this as input to another table to delete records

I have table1 with columns:
def_id, def_name, username etc
I have another table table2 which has some association:
assoc_id,parent_id,child_id
The parent_id , child_id are actually def_id's from Table1 . They get inserted into Table2 based on parent_child relation user action in GUI.
Now I want to select all def_id for a particular username from Table1 and then use that input to delete all the records if those def_ids are part of the parent_id or child_id from Table2.
How do I do this in SQL? I am using Sybase database.
Any help will be appreciated
Delete Table2
Where parent_id In
(Select def_id from table1
Where username = #username) Or
child_id In
(Select def_id from table1
Where username = #username)
Or
Delete t2
From table2 t2
Where Exists
(Select * From Table1
Where def_id In
(t2.parent_Id, t2.child_Id))
An easy way is adding a subquery to the where clause.
DELETE ab
FROM AuthorArticle AS ab
WHERE ab.AuthID=(SELECT AuthID FROM Authors WHERE AuthorLastName='Yin')
Never used Sybase, but this is basic SQL and should work.
Try:
DELETE table2
FROM table2
INNER JOIN table1 ON table1.def_id IN (table2.parent_id, table2.child_id)

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

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)

Help regading not in and inner join

I have two tables. Table1 and Table2
Table1
id tid
1 100
2 200
3 300
Table2
tid name
100 A
200 B
I want to take out id of records from Table1 whichever's tid is not present in Table2.
My output should be like this.
Table1.id
3
For this i have written following queries but it is taking too much of time. Since
both tables have more amount of records.
please help me how to write a query for this such a way that it will take less amount of time.
select id from Table1 where tid not in (select tid from Table2)
select a.id from Table1 a inner join Table2 b on a.tid<>b.tid
TIA.
Use a left join, and then use the WHERE clause to filter only to rows where the join didn't work:
SELECT
a.ID
from
Table1 a
left join
Table2 b
on
a.tid = b.tid
where
b.tid is null
Of course, this still might not work fast enough, in which case you need to check whether you have indexes on the tid columns in these two tables.
How about
select id
from table1
where tid IN (
select tid from table1
minus
select tid from table2
)
set operations (minus part above) are pretty fast in Oracle
First create indexes:
CREATE INDEX t1_tid ON table1 (tid ASC);
CREATE INDEX t2_tid ON table2 (tid ASC);
This way it could be faster.
Regarding the query, what about:
SELECT tid FROM table1
MINUS
SELECT tid FROM table2
You can try "not exists" too:
select *
from Table1 T1
where not exists (select 1
from Table2 T2
where T1.tid=t2.tid
);