Is there any better way to write this query - sql

I designed below query for my delete operation. I am new to SQL and just wanted to check with experienced people here if it is fine or any better way to do this. I am using DB2 database
DELETE FROM TableD
WHERE B_id IN
(
SELECT B.B_id
FROM TableB tB
INNER JOIN TableA tA
ON tB.A_id = tA.A_id
WHERE A_id = 123
) AND
C_id IN (1,2,3)
This has two IN clause which I am little worried and not sure if I could use EXISTS clause anywhere.
Database Structure as below:
Table A has ONE TO MANY relation with Table B
Table B has ONE TO MANY relation with Table C
Table B has ONE TO MANY relation with Table D
Table D has composite primary key ( B_id, C_id )
Table D data somewhat similar to below
B_id|C_id
----------
1 | 1
1 | 2
1 | 3
2 | 4
2 | 5
3 | 5
Here I have to delete rows which have C_id in array of values. But since the index is a composite of B_id and D_id, I am retrieving related B_id to the particular entity of Table A by equality operator A_id=123

There isn't necessarily anything wrong with your method. However, a useful alternative technique to know is merge:
merge into TableD
using (
select distinct
B.B_id
from TableB tB
inner join TableA tA on
tB.A_id = tA.A_id and
A_id = 123
) AB
on
TableD.B_id = AB.B_id and
C_id in (1,2,3)
when matched then delete;
Note that I had to use distinct on the inner query to prevent duplicate matches.

You can use merge like this too :
merge into TableD
using TableB tB
on B.B_id = TableD.B_id
and tB.A_id in (select A_id from TableA tA where A_id = 123)
and C_id in (1,2,3)
when matched then delete;

DELETE FROM TableD tD
WHERE
EXISTS (
SELECT
tB.B_id
FROM
TableB tB
WHERE
A_id = 123
AND tB.B_id = tD.B_id
)
AND C_id IN (1, 2, 3)

Related

Postgres Relationship query

I have two tables A and B where the relationship is one to many (A -> many B). Table "A" contains columns id, name and table "B" has id, a_id(fk), is_off(boolean).
Now, I want to get id of "A" which has all "B"'s is_off = true.
I tried this one select a.id from A a inner join B b on a.id = b.a_id where b.is_off = true But it only returns even if an "A" has an item (B) which has is_off = false;
Any help will be appreciated.
You were close. A subquery is probably what you're looking for:
Test data
CREATE TABLE a (id int PRIMARY KEY, name text);
CREATE TABLE b (id int, a_id int REFERENCES a(id), is_off boolean);
INSERT INTO a VALUES (1,'foo');
INSERT INTO b VALUES (42,1,true),(1,1,false);
Your query would return all records if at least one of the b records fulfil your join and where clauses:
SELECT * FROM a
JOIN b on a.id = b.a_id
WHERE b.is_off;
id | name | id | a_id | is_off
----+------+----+------+--------
1 | foo | 42 | 1 | t
(1 Zeile)
If you intend to exclude all a records that contain at least one is_off = true, you can use NOT IN with a subquery, but as suggested by #a_horse_with_no_name (see comments below) you could use EXISTS or NOT EXISTS:
SELECT * FROM a
WHERE NOT EXISTS (SELECT a_id FROM b WHERE a.id = b.a_id AND is_off);
id | name
----+------
(0 Zeilen)

SQL query with both table columns-Oracle

There are two tables named, for an example A and B.
A and B has a unique column named key_ref. and key_ref is the primary key of both tables
I need to find records in A but not in B. Therefore I wrote a query like,
SELECT a.*,b* from A a,B b WHERE key_ref NOT IN (SELECT key_ref from B)
The issue with this is, I do not get the empty columns of table B for the result. My result should include all the columns of A and B.
If I write my query like following my results get wrong. Is there any way , where I can achieve this even with a join condition.
SELECT a.* from A a WHERE key_ref NOT IN (SELECT key_ref from B)
Please refer following example.
Table A Table B
key ref col1 key ref col2
A aaa A aaa
B bbb B bbb
C ccc C ccc
D ddd
My answer should be,
key ref col1 col2
D ddd
If I understand your request:
You can use a LEFT OUTER JOIN operation so you'll get all rows in A not present in B (with condition in WHERE b.key_ref IS NULL)
Try this:
SELECT *
FROM a
LEFT OUTER JOIN b
ON a.key_ref = b.key_ref
WHERE b.key_ref IS NULL
Is this what you need:
select * from A
except
select * from B
?
If the second table tableB doesn't have a record associated with first table, then how would you display record from second table tableB which are not exists in the first table tableA.
So, the one way is to include NULL as columns ref. to tableB like that :
select a.*, null col2
from tableA a
where not exists (select 1 from tableB b where b.key_ref = a.key_ref);

SQL: select all unique values in table A which are not in table B

I have table A
Id | Name | Department
-----------------------------
0 | Alice | 1
0 | Alice | 2
1 | Bob | 1
and table B
Id | Name
-------------
0 | Alice
I want to select all unique Ids in table A which do not exist in table B. how can I do this?
select distinct id
from TableA a
where not exists (
select id
from TableB
where id = a.id
)
Just to provide a different solution than NOT IN :
SELECT DISTINCT A.Id
FROM A
LEFT OUTER JOIN B
ON A.Id = B.Id
WHERE B.Id IS NULL
The "good" solution is usually MINUS or EXCEPT, but MySQL doesn't support it.
This question was asked a few time ago and someone posted an article comparing NOT IN, NOT EXISTS and LEFT OUTER JOIN ... IS NULL. It would be interesting if someone could find it again!
The most efficient answer is to use a left join, as using "NOT IN" can sometimes prevent a query from using an index, if present.
The answer in this case would be something like
SELECT DISTINCT
*
FROM
TableA a
LEFT JOIN
TableB b
ON
a.Id = b.Id
WHERE
b.Id IS NULL
Alternatively, this is more readable than a left join, and more efficient than the NOT IN solutions
SELECT * FROM TableA a where NOT EXISTS (SELECT * FROM TableB where Id = a.Id)
I'd use a NOT EXISTS Like this:
SELECT A.Id
FROM TableA A
WHERE NOT EXISTS (SELECT B.Id FROM TableB B WHERE A.Id = B.Id)
GROUP BY A.Id
SELECT DISTINCT Id FROM A WHERE Id NOT IN (SELECT ID FROM B);
SELECT DISTINCT Id FROM A WHERE Id NOT IN(SELECT DISTINCT Id FROM B);
The subquery will get all the IDs in B. The group by...having will get all the unique IDs in A that are also not in B.
select *
from A
where id not in
(
select distinct id
from B
)
group by ID
having count(*) > 1;

SQL: Single select query from 2 Non-Joining tables

I have 2 tables which doesn't have any references to each other and I'm trying to create a third table (for reference lookup) by selecting from fields from both tables.
TableA has an A_ID
TableB has a B_ID
I want to create Table C which has a 1 to 1 reference between A_ID to B_ID
where A_ID = FirstID and B_ID = SecondID, I can't join the 2 tables because there's nothing in common.
Something like:
Insert INTO [TableC]
(FirstID, SecondID)
SELECT
A_ID As FirstID,
(Select B_ID From TableB)
FROM TableA
Basically we are creating a relationship right now with Table C so that we can use it to reference the two tables in the future using the their IDs.
Assuming TableA and TableB truly have nothing in common, then what you want is the Cartesian product, that is, for every row in A times every row in B.
INSERT INTO TableC(FirstID,SecondID)
SELECT A_ID,B_ID
FROM TableA
CROSS JOIN TableB
Perhaps what you really want is to join them by ROW_NUMBER().
INSERT INTO TableC(FirstID,SecondID)
SELECT A_ID,B_ID
FROM (SELECT A_ID,ROW_NUMBER() OVER (ORDER BY whatever) as rownumA FROM TableA) a
FULL OUTER JOIN (SELECT B_ID,ROW_NUMBER() OVER (ORDER BY whatever) as rownumB FROM TableB) b ON a.rownumA=b.rownumB

Querying with foreign key

Say I have 2 tables whose structures are as follows:
tableA
id | A1 | A2
tableB
id | tableA_id (foreign key) | B1
Entries in A have a one-to-many relationship with entries in B. What kind of query operation would I need to achieve "something like this: select all objects from table B where A1="foo""? Basically, apply a query on tableA and from those result, find corresponding dependent objects in tableB
That would be best performed with a join:
select
B.*
from
tableB as B
join tableA as A
on B.tableA_id=A.id
where
A1='foo'
SELECT * FROM tableB WHERE tableA_id IN (SELECT id FROM tableA WHERE A1 = "foo");
Subqueries my friend.
The work fine on MySQL and Oracle. Don't know about SQL Server. Hope is what you are looking for.
You need to join table A and B and issue a query on the result:
select * from
tableA join tableB
ON tableA.A1 = tableB.tableA_id
WHERE tableA.A1 = 'foo'