DELETE multiple tables where at least one is empty - mysql

I'm deleting certain rows from multiple tables like this:
I would like to clean up certain tables after an entry from the main table has been removed. I know the ID of that entry (which is the fid in all other tables) but not every table contains related data.
This is what I came up with:
DELETE a, b, c
FROM tableA AS a
LEFT JOIN tableB AS b
ON a.fid = b.fid
LEFT JOIN tableC AS c
ON a.fid = c.fid
WHERE a.fid = 123
This only works if tableA contains at least one row with a fID of 123
How can I delete remove certain rows from tableB and tableC when tableA has no matching row?

I think the easiest approach is three delete statements:
delete tableA where fid = 123;
delete tableB where fid = 123;
delete tableC where fid = 123;
If you want to do this as one statement, use left outer join but start with the list of ids to delete:
delete a, b, c
from (select 123 as fid
) todelete left outer join
tableA a
on todelete.fid = a.fid left outer join
tableB b
on todelete.fid = b.fid left outer join
tableC c
on todelete.fid = c.fid;

Untested Query using + operator as in Oracle.
Check if it would help:
DELETE a, b, c
FROM tableA AS a , tableb as b, tableC as c
and a.fid = b.fid(+)
and a.fid = c.fid(+);

Related

Delete using Select Inner Join from Same Table

I am trying to Delete from Table A where the ID exists in a Select Inner Join that includes Table A similar to:
Delete from TableA where ID in
(Select Distinct A.ID from TableA A
Inner Join TableC C
Inner Join TableJ J
Inner Join Table J J2
On J.VendorID=J2.VendordID
and J.Title=J2.Title
and A.C_ID=C.C_ID
and J.ID=A.J_ID
and J2.ID=C.J_ID)
The Select works like I want (amazingly) but I keep getting the error
1093 - You can't specify target table 'TableA' for update in FROM clause
Which I assume means you can't try to delete from a table that is included in your subquery. Is there anyway to restructure this so I can?
You don't need to use a subquery.
Delete A from TableA A
Inner Join TableC C
Inner Join TableJ J
Inner Join TableJ J2
On J.VendorID = J2.VendordID
and J.Title = J2.Title
and A.C_ID = C.C_ID
and J.ID = A.J_ID
and J2.ID = C.J_ID

MySQL How to do a 3 table join

I'm trying to perform a 3 table join on MySQL in order to achieve something like the diagram below.
The main problem I'm having is that I only want to work with the records of table A which has 100 records so if there are no relationships for the right tables I would like to see a null.
This all works fine when only table A and B are involved but when I try to do the third join with C I'm getting more than the original 100 records, I'm getting 130 which I believe is because is adding the records that match B-C with duplicate data from table A.
What am I missing?
This is the SQL I currently have that returns correctly 100 records
SELECT count(A.id)
FROM tableA A
LEFT JOIN TableB B ON B.id = A.b_id
This is what I'm trying to do that is returning more than the original 100 records for Table A.
SELECT count(A.id)
FROM tableA A
LEFT JOIN TableB B ON B.id = A.b_id
LEFT JOIN TableC C ON C.id = B.c_id
This could be resolved by a JOIN to a subquery rather than a table.
If you had unique Ids to join to, it would simply be like you've tried already (arbitrary example):
SELECT * from table1 t1
LEFT JOIN table2 t2 on t2.id = t1.id
LEFT JOIN table3 t3 on t3.id = t2.id
If, however the id field in table3 wasn't unique, you'd get multiple rows for each duplicate. You could resolve this by:
SELECT * from table1 t1
LEFT JOIN table2 t2 on t2.id = t1.id
LEFT JOIN (SELECT * FROM table3 GROUP BY id) t3 on t3.id = t2.id
So, using your example (assuming only the third join has duplicates), something like:
SELECT count(A.id)
FROM tableA A
LEFT JOIN TableB B ON B.id = A.b_id
LEFT JOIN (SELECT * FROM TableC GROUP BY id) C ON C.id = B.c_id
...should do the trick. This is down to assumption of your table and data structure, so you might want to make the asterisk more explicit.
SELECT count(distinct A.id)
FROM tableA A
LEFT JOIN TableB B ON B.id = A.b_id
LEFT JOIN TableC C ON C.id = B.c_id

SQL Join over two tables

here is my problem:
I have two tables. Every entry of table A has several entries in table B matched over an ID. I now want to get all entries of table A with one data entry of table B - the one with the highest ID in this table.
Table A has an ID
Table B has an own ID and ID_OF_TABLE_A (for the relation between both)
Table A has one to many relation to Table B. I want all Entries of Table A, matched with the one with the highest ID out of B. Is there any way to realize this in an SQL Statement? I tried all kinds of joins since I need the information of that matched entry in the outcome of the select.
How about
SELECT *
FROM tableA a
INNER JOIN tableB b ON a.ID = b.ID_OF_TABLE_A
WHERE b.ID = (SELECT MAX(ID) FROM tableB c WHERE b.ID = c.ID)
Try this:
SELECT a.*, b.*
FROM tableA a
LEFT OUTER JOIN (SELECT b.*
FROM tableB b
INNER JOIN (SELECT ID_OF_TABLE_A, MAX(ID) bID
FROM tableB
GROUP BY ID_OF_TABLE_A
) c ON b.ID_OF_TABLE_A = c.ID_OF_TABLE_A AND b.ID = c.bID
) AS b ON a.ID = b.ID_OF_TABLE_A;
You can use an inline view where you filter the rows you need from table b with the help of the grouping clause and max function like so:
select a.*, b.*
from a
join (
select max(id) as id_b_max, id_a
from b
group by id_a
) b
on a.id = b.id_a;
Tested with:
create table a(id int);
create table b(id int, id_a int);
insert a values (1);
insert b values(1, 1);
insert b values(2, 1);
insert b values(3, 1);
select a.id, max(b.id)
from table_a a join table_b b on a.id = b.table_a_id
group by a.id
This should work. prefilter out the max id of the ID_OF_TABLE_A. and then join on that id.
SELECT A.*, B.*
FROM A
INNER JOIN ( SELECT max( ID ) AS id, ID_OF_TABLE_A
FROM B
GROUP BY ID_OF_TABLE_A) AS grp_b
ON grp_b.ID_OF_TABLE_A = a.ID
INNER JOIN B ON b.ID = grp_b.id

Get distinct value from join query (Join Table)

How get a distinct value form more than one table (inner join query).
Eg,
select a.id,b.name,c.address
from table1 a
inner join table2 b on (a.id = b.row_id)
inner join table3 c on (a.id = c.ticket_id)
where c.status = 'open';
Here the scenario is for example, two rows contain the same a.id value so how to get the distinct value from a.id.
Somebody help me that how to get?
just add Distinct ...
select DISTINCT a.id,b.name,c.address
from table1 a
inner join table2 b on (a.id = b.row_id)
inner join table3 c on (a.id = c.ticket_id)
where c.status = 'open';
i think this is works fine..
if you need only one record distinct then it should be like this...
SELECT DISTINCT(cat_id) FROM PRODUCTS WHERE brand_id = 'sony'

SQL LEFT JOIN only newest right column entry?

So I have two tables like this:
create table A
{
id int;
...
}
create table B
{
id int;
a_id int;
t timestamp;
...
}
A is one-to-many with B
I want to:
SELECT * FROM A LEFT JOIN B ON A.id = B.a_id ???
But I want to return exactly one row for each entry in A which has the B with the newest t field (or null for Bs fields if it has no B entry).
That is rather than returning all A-B pairs, I want to only select the newest one with respect to A (or A-null if no B entry).
Is there some way to express this in SQL? (I'm using MySQL 5.5)
LEFT JOIN is only concerned with ensuring every row in A is returned, even if there is no corresponding joined row in B.
The need for just one row needs another condition. MySQL is limitted in its options, but one could be:
SELECT
*
FROM
A
LEFT JOIN
B
ON B.id = A.id
AND B.t = (SELECT MAX(lookup.t) FROM B AS lookup WHERE lookup.id = A.id)
Another could be...
SELECT
*
FROM
A
LEFT JOIN
(
SELECT id, MAX(t) AS t FROM B GROUP BY id
)
AS lookup
ON lookup.id = A.id
LEFT JOIN
B
ON B.id = lookup.id
AND B.t = lookup.t
You could do the following:
SELECT A.*, B.*
FROM
A
LEFT JOIN
(SELECT B.a_id, MAX(t) as t FROM B GROUP BY B.a_id) BMax
ON A.id = BMax.a_id
JOIN B
ON B.a_id = BMax.a_id AND B.t = BMax.t
you first need to get the newest t from tableB in a subquery, then join it with tableA and tableB.
SELECT a.*, c.*
FROM tableA a
LEFT JOIN
(
SELECT a_ID, max(t) maxT
FROM tableB
GROUP BY a_ID
) b on a.a_id = b.a_ID
LEFT JOIN tableB c
ON b.a_ID = c.a_ID AND
b.maxT = c.t
try this:
SELECT *
FROM tableA A LEFT JOIN
(select a_id ,max(t) as max_t
from tableB
group by a_id )b
on A.id = b.a_id
and A.t=b.max_t