Querying with foreign key - sql

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'

Related

Join of Two Tables where Data Matches in One Column

For some reason I have a hard time grasping joins and this one should be very simple with the knowledge that I have in SQL.
Anyway, I have 2 tables. We will call them TableA and TableB. One of the columns in TableA is "ID". TableB only consists of the column "ID". I want to return all rows in TableA whose ID is present in TableB.
I know this should be very simple to figure out, but my brain doesn't want to work today.
You can do this using an EXISTS:
Select A.*
From TableA A
Where Exists
(
Select *
From TableB B
Where A.Id = B.Id
)
You can also use a JOIN if you wish, but depending on your data, you may want to couple that with a SELECT DISTINCT:
Select Distinct A.*
From TableA A
Join TableB B On A.Id = B.Id
One thing to keep in mind is that the ID of TableA is not necessarily related to the ID of TableB.
this should work
SELECT B.ID
FROM TableA A
JOIN TableB B
ON (A.ID=B.ID)
WHERE A.ID=B.ID
You can also use IN operator like this:
Select *
From TableA
Where ID in
(
Select distinct ID
From TableB
)

Is there any better way to write this query

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)

Join and showing different columns from tables

I have a simple SQL question, I thought it would be quite straight forward but have got myself in a muddle. Any help would be appreciated
I have table A which contains a last updated
Table A has a one to many with Table B
Table B has a one to many with Table C
I want to show all rows of table C with the last updated time from table A. I have tried some joins but they dont seem to be quite working. Ideally I want somehting like
select a.lastUpdated c.* from TableA a, TableC c where
a.id in (select a_id from TableB where (select b_id from TableC where c_id = select
id from TableC where XXXX=YYYY))
so I can pass in an id for table C and then get one row returned with the last updated time present.
XXX=YYY would be my criteria for returning one row of table C.
Any help or pointers appreciated
Thanks
Something like
SELECT c.*
FROM TableA AS a
INNER JOIN TableB AS b
ON a.a_id = b.b_id
INNER JOIN TableC AS c
ON b.b_id = c.c_id
WHERE a.lastUpdated = c.lastUpdated;
Should work. This is a situation where a striaght INNER JOIN should suffice; unless of course I have missed something.
I hope this helps.
You should be able to do this by joining A and B together, aggregating the results at the c_id level, and then joining in C:
select tc.*, maxlastupdated
from tablec tc left outer join
(select tb.c_id, max(lastupdated) as maxlastupdated
from tablea ta join
tableb tb
on ta.b_id = tb.b_id
group by ta.id
) ta
on tc.c_id = ta.c_id
You need to drive your SQL query from Table C.
The query below displays the updated timestamp column from table A.
Since it is a one-to-many in the direction of tables A --> B --> C
You will inevitably end-up with a lot of rows in table C - all with the same timestamp.
SELECT c.*, a1.update_timestamp
FROM table_c c, table_b b, table_a a1
WHERE c.join_column = b.join_column
AND b.join_column = a1.join_column
AND a1.update_timestamp =
(SELECT max(a2.update_timestamp) FROM table_a a2
WHERE a2.<identifying columns> = a1.<identifying columns>
);

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 select statement with a group by

I have data in 2 tables, and I want to create a report.
Table A:
tableAID (primary key)
name
Table B:
tableBID (primary key)
grade
tableAID (foreign key, references Table A)
There is much more to both tables, but those are the relevant columns.
The query I want to run, conceptually, is this:
select TableA.name, avg(TableB.grade) where TableB.tableAID = TableA.tableAID
The problem of course is that I'm using an aggregate function (avg), and I can rewrite it like this:
select avg(grade), tableAID from TableB group by tableAID
but then I only get the ID of TableA, whereas I really need that name column which appears in TableA, not just the ID.
Is it possible to write a query to do this in one statement, or would I first need to execute the second query I listed, get the list of id's, then query each record in TableA for the name column... seems to me I'm missing something obvious here, but I'm (quite obviously) not an sql guru...
You can do this:
SELECT avg(b.grade), a.tableAID, a.name
FROM TableA a
JOIN TableB b
ON b.tableAID = a.tableAID
GROUP BY a.tableAID, a.name
Just adding it to the group will work fine in your case.
SELECT AVG(TableB.grade), TableB.tableAID, TableA.Name
FROM TableA INNER JOIN TableB
ON TableA.TableAID = TableB.TableAID
GROUP BY TableA.tableAID, TableA.Name
Alternative answer:
SELECT AVG(b.grade), a.tableAID, MAX(a.name )
FROM TableA a
JOIN TableB b
ON b.tableAID = a.tableAID
GROUP BY a.tableAID
Just to get you thinking.