Mysql delete in one table by id's from another table - mysql

I have two tables:
A
id | name
and
B
id | name
On B table i create query to select all data, where id's are in (... some values), but how can i in one query select this B - id's and delete from A where A.id = B.id ?
I'm new to sql.... Could not find how to combine all in one query...
*i must select from b on some like query, for example my b query: select * from B where somefieldinteger in (1,4,9,21,25) and that b.id must compare with a*
upd
this throw error
delete `LINK_LA_TYP` FROM `LINK_LA_TYP` JOIN `LINK_ART` ON `LINK_LA_TYP`.LAT_LA_ID=`LINK_ART`.LA_ID JOIN `ARTICLES` ON `LINK_ART`.LA_ART_ID=`ARTICLES`.ART_ID WHERE (`ARTICLES`.ART_SUP_ID in (10008,10439,11005,10097,10669,11100,80,10912,10683,10675,10194,11196,1166,10730,10248,10870,11200,11059,247,10121,10911,489,10724,496,10093,10205,1318,10953,11199,11047,128,114,194,10865,11058,10345,1286,10667,10064,11077,10622,11205,10917,10344,495,10709,10954,10744,304,10957,10447,10764,10129,10862,10918,10731,11115,10095,10859,10580,1345,10177,10323,144,11182,10132,256,10941,58,10006,10017,10780,10765,10665,11110,10714,10224,750,10267,10179,10725,10774,11063,10868,10103,10676,10057,10649,255,10322,11022,309,10754,11121,10801,10018,11004,10245,146,11056,381,10781,10699,11120,11126,830,10240,11162,10436,10584,10342,10861,11190,10721,11171,10564,10545,94,10087,73,10755,10869,10547,10706,10346,444,426,10059,153,122,10674,64,113,11101,10231,10337,806,11117,10385,251,11188,491,11192,100,10792,10069,10864,11099,10246,10178,10758,10568,10230,10124,10384,10782,10726,384,10670,305,10763,10768,10585,10394,10552,498,10677,1348,168,10814,10582,10382,11093,11173,10381,427,441)) limit 50

Use delete together with join like this:
mysql> create table a (id int);
mysql> insert into a values (1), (2), (3), (4);
mysql> create table b (id int);
mysql> insert into b values (2), (3);
mysql> delete a from a join b on a.id=b.id where b.id > 2;
mysql> select * from a;
+------+
| id |
+------+
| 1 |
| 2 |
| 4 |
+------+
This scales to arbitrary number of tables, e.g.:
DELETE a
FROM a
JOIN b ON a.idA=b.idA
JOIN c ON b.idB=c.idB;
This will delete from a all records that are referred from those records of b which are in turn referred from c. You may also add WHERE clause like this:
DELETE a
FROM a
JOIN b ON a.idA=b.idA
JOIN c ON b.idB=c.idB
WHERE a.status='done' AND
b.status='open' AND
c.status='open';
If you want to limit number of rows to be deleted, do like this:
DELETE a
FROM a
JOIN b ON a.idA=b.idA
JOIN c ON b.idB=c.idB
LIMIT 500000;
If you want to delete first 500000 rows, you need to refine which rows are first, so you need to establish some ordering among rows. In other words you need to sort rows by some criteria and then limit like this:
DELETE a
FROM a
JOIN b ON a.idA=b.idA
JOIN c ON b.idB=c.idB
ORDER BY a.something
LIMIT 500000;

delete from A where exists (select 1 from B where A.id=B.id and B.criteria=true)
If you leave out ... and B.criteria=true it would delete all rows in A that appear in B; otherwise you delete whatever matches your criteria.

Related

mysql update table column from another table with CONCAT

I am trying to work out how to perform an SQL UPDATE table column from Table A into Table B. The problem I have is trying to concat multiple values from Table A Column X into Table B Column Y
TableA Structure
id | Interest
1 | Bowling
2 | Swimming
1 | Basketball
TableB Structure
id | Interest_new
1 | null
2 | null
I want Table B to have following data
TableB
id | Interest_new
1 | Bowling,Basketball
2 | Swimming
This is my attempt with SQL query but it doesn't concat , just updated table B with first match
UPDATE TableB
INNER JOIN TableA ON TableB.id= TableA.id
SET TableB.id=CONCAT(TableA.id, ',')
where TableA.id= TableB.id;
You probably intend to use GROUP_CONCAT here, as you want an aggregated CSV output:
UPDATE TableB b
INNER JOIN
(
SELECT id, GROUP_CONCAT(Interest ORDER BY id) Interests
FROM TableA
GROUP BY id
) a
ON a.id = b.id
SET
Interest_new = a.Interests;
However, I actually advocate not even doing this, as storing CSV in your SQL tables is a generally bad idea. Consider just making a view of this data instead:
CREATE VIEW newInterests AS
SELECT id, GROUP_CONCAT(Interest ORDER BY id) Interests
FROM TableA
GROUP BY id;

need an efficient query for selecting from two tables

One table A, looks like this:
table A:
==========
ID NAME
1 Ted
2 John
3 Sandy
4 Robert
5 Helen
table B:
=========
CONTRIBUTION CONTRIBUTOR_ID
100 1
200 3
150 3
270 2
30 1
Assuming table B is very big and table A is small, I would like to pseudo iterate on this.
- take first ID from table A
- search for the first occurrence in table B, if found add to result
- if not continue to next ID in table A.
- repeat until end of table A
I would like a list of all ID's from table A that exist in table B
So the result here would be:
1
2
3
Of course, the tables are properly indexed.
any idea how to write this efficiently in MySQL?
Thanks
Or just simply
select distinct contributor_id
from table B
select distinct ID from tableA inner join tableB
on table.ID=tableB.CONTRIBUTOR_ID
Try this:
select tA.ID
from tableA tA inner join tableB tB on tA.ID = tB.CONTRIBUTOR_ID
group by tA.ID
the query
SELECT * from A,B where A.ID = B.CONTRIBUTOR_ID
would select all rows with an existing ID in both tables. It would leave out all rows in A which never have contributed (not exist in B)
EDIT:
to only get the IDs of those who ever contributed, try:
SELECT ID FROM A WHERE EXISTS (SELECT CONTRIBUTOR_ID FROM B where ID = CONTRIBUTOR_ID)
If table B can contain contributors that don't exist in table A, then I suggest trying:
select tA.ID
from tableA tA
inner join (select distinct contributor_id from tableB) tB
on tA.ID = tB.CONTRIBUTOR_ID
(assuming you have an index on Contributor_ID on tableB)
Can be done by using subquery
Select distinct ID from A where ID in(select CONTRIBUTOR_ID from B)

How does Left Join / IS NULL eliminate records which are there in one table and not in the other?

I am having a tough time to understand why does LEFT JOIN / IS NULL eliminate records which are there in one table and not in the other.
Here is an example
SELECT l.id, l.value
FROM t_left l
LEFT JOIN t_right r
ON r.value = l.value
WHERE r.value IS NULL
Why should r.value = NULL eliminate records ? I am not understanding . I know I am missing something very basic but at present I cant figure out even that basic one. I would appreciate if someone explains it to me in detail .
I want a very basic explanation.
This could be explained with the following
mysql> select * from table1 ;
+------+------+
| id | val |
+------+------+
| 1 | 10 |
| 2 | 30 |
| 3 | 40 |
+------+------+
3 rows in set (0.00 sec)
mysql> select * from table2 ;
+------+------+
| id | t1id |
+------+------+
| 1 | 1 |
| 2 | 2 |
+------+------+
2 rows in set (0.00 sec)
Here table1.id <-> table2.t1id
Now when we do a left join with the joining key and if the left table is table1 then it will get all the data from table1 and in non-matching record on table2 will be set to null
mysql> select t1.* , t2.t1id from table1 t1
left join table2 t2 on t2.t1id = t1.id ;
+------+------+------+
| id | val | t1id |
+------+------+------+
| 1 | 10 | 1 |
| 2 | 30 | 2 |
| 3 | 40 | NULL |
+------+------+------+
3 rows in set (0.00 sec)
See that table1.id = 3 does not have a value in table2 so its set as null
When you apply the where condition it will do further filtering
mysql> select t1.* , t2.t1id from table1 t1
left join table2 t2 on t2.t1id = t1.id where t2.t1id is null;
+------+------+------+
| id | val | t1id |
+------+------+------+
| 3 | 40 | NULL |
+------+------+------+
1 row in set (0.00 sec)
Let's assume r-table is employees, and r_table is computers. Some employees don't have computers. Some computers are not assigned to anyone yet.
Inner join:
SELECT l.*, r.*
FROM employees l
JOIN computers r
ON r.id = l.comp_id
gives you the list of all employees who HAVE a computer, and the info about computer assigned for each of them. The employees without a computer will NOT appear on this list.
Left join:
SELECT l.*, r.*
FROM employees l
LEFT JOIN computers r
ON r.id = l.comp_id
gives you the list of ALL employees. The employees with computer will show the computer info. The employees without computers will appear with NULLs instead of computer info.
Finally
SELECT l.*, r.*
FROM employees l
LEFT JOIN computers r
ON r.id = l.comp_id
WHERE r.id IS NULL
Left join with the WHERE clause will start with the same list as the left join (2), but then it will keep only those employees that do not have corresponding information in the computer table, that is, employees without the computers.
I this case, selecting anything from the r table will be just nulls, so you can leave those fields out and select only stuff from the l table:
SELECT l.*
FROM ...
Try this sequence of selects and observe the output. Each next step builds on the previous one.
Please let me know if this explanation is understandable, or you'd like me to elaborate some more.
EDITED TO ADD:
Here's sample code to create the two tables used above:
CREATE TABLE employees
( id INT NOT NULL PRIMARY KEY,
name VARCHAR(20),
comp_id INT);
INSERT INTO employees (id, name, comp_id) VALUES (1, 'Becky', 1);
INSERT INTO employees (id, name, comp_id) VALUES (2, 'Anne', 7);
INSERT INTO employees (id, name, comp_id) VALUES (3, 'John', 3);
INSERT INTO employees (id, name) VALUES (4, 'Bob');
CREATE TABLE computers
( id INT NOT NULL PRIMARY KEY,
os VARCHAR(20) );
INSERT INTO computers (id, os) VALUES (1,'Windows 7');
INSERT INTO computers (id, os) VALUES (2,'Windows XP');
INSERT INTO computers (id, os) VALUES (3,'Unix');
INSERT INTO computers (id, os) VALUES (4,'Windows 7');
There are 4 employees. Becky and John have computers. Anne and Bob do not have a computer. (Anne, has a comp_id 7, which doesn't correspond to any row in computers table - so, she doesn't really have a computer.)
the left returns all the row from the left table
ON r.value = l.value
if there is no r.value for a l.value then the r is empty
r.value is null will be true
in your example, the result would be EVERY record from t_left, as well as every matching record from t_right where they both have the same value. where there is no match, NULL values are given instead of values from t_right. where r.value is null simply eliminates the rows that did match, by detecting those null values.
essentially saying 'give me the rows from t_left that DONT match rows in t_right
a right join performs the reverse order of the left join.
This is based on the difference between INNER JOIN and LEFT JOIN. When you use an INNER JOIN, the result only contains rows that match between the two tables (based on the ON condition).
But when you use a LEFT JOIN, you also get rows in the result for all rows in the first table that don't have a match in the second table. In these cases, all the result columns from the second table are filled with NULL as a placeholder.
The WHERE r.value IS NULL test then matches these rows. So the final result only contains the rows with no match.
LEFT JOIN takes the values on the left and tries to match the table on the left by the column specified on ON if it doesn't find a match then it interprets the right table's columns as NULL. hence only those that can't find a match on the right table will be selected by IS NULL operator
Firstly a left join states that all records from the left table will be include, and only those from the right that match.
So lets say you have a red, blue and green sock in your drawer, and your friend only a red, yellow and blue, a left join from your drawer to your friends would return all the socks from your drawer (red, blue and green) and only matching ones from your friends (red and blue).
Now the IS NULL part says that you want to see all socks from your drawer, where there are not matching pair partners in your friends drawer, so from all your socks the only one with a missing pair is the green sock.
This sentence:
SELECT l.id, l.value
FROM t_left l
LEFT JOIN t_right r
ON r.value = l.value
will have all the elements from t_left table joined to all elements from t_right table. As you probably will now, in an INNER JOIN only rows which matches both tables will be shown, so t_left could have less rows than all the possible rows. In a LEFT JOIN, you have ALL THE ROWS from t_left table plus the matched rows from t_right (if they can be joined). So, what happens with rows in t_left that not matches any t_right row? All the fields from t_right table that would be supposed to contain data will be filled with NULL values. So, if you only select NULL values from right table, you'll find all the values from the t_left table that has no match on the right one, XD
Left join gives all records from left table. If the any key present in left table is missing in right table all right table column will be null, but all the left table values will be present.
It is the basic difference between inner join and left / right join.
Thus when you do 'r.value = null` you get those records from left where there is no matching key in right table.
HTH.
It's Simple Left join funda.....
following Query get all the record from left table and matched record From Right table if it doesn't match than it will return NUll value. at The end you filter data by using where condition which return values that are in Left table but not in right table
SELECT l.id, l.value
FROM t_left l
LEFT JOIN t_right r
ON r.value = l.value
WHERE r.value IS NULL
SELECT * FROM a LEFT JOIN b ON a.v = b.v ... WHERE b.id IS NULL
it's super simple logic:
select from table "a"
join table "b" (if matching rows exists - ON a.v=b.v otherwise use NULL's as values)
WHERE condition: if something is missing (b.id IS NULL) = OK.

Duplicate column name error during union

I'm using this query to count rows resulting from 2 tables using union and an alias at the end of the query but it's not working:
SELECT COUNT(*) FROM (
(SELECT * FROM bills INNER JOIN cats INNER JOIN suppliers
INNER JOIN new_cards
WHERE new_cards.`Card_Code` LIKE '%8%'
AND bills.`Sup_ID` = suppliers.`Sup_ID`
AND new_cards.`Sup_ID` = suppliers.`Sup_ID`
AND cats.`Cat_ID` = bills.`Cat_ID`
AND bills.`Cat_ID` = cats.`Cat_ID`
AND new_cards.`Bill_ID` = bills.`Bill_ID`)
UNION
(SELECT * FROM bills INNER JOIN cats INNER JOIN suppliers
INNER JOIN sold_cards WHERE
sold_cards.`Card_Code` LIKE '%8%'
AND bills.`Sup_ID` = suppliers.`Sup_ID`
AND sold_cards.`Sup_ID` = suppliers.`Sup_ID`
AND cats.`Cat_ID` = bills.`Cat_ID`
AND bills.`Cat_ID` = cats.`Cat_ID`
AND sold_cards.`Bill_ID` = bills.`Bill_ID`)
) w
the error is
Error Code: 1060
Duplicate column name 'Cat_ID'
Seems you have a column called Cat_ID in both cats and bills tables. When you do a select * on a join on the tables you will get duplicate column names.
Some possible solutions:
Rename the Cat_ID column in one of the tables
Explicitly name the columns in your select, i.e. instead of "*" use "bills.Cat_ID AS new_name, ...."
These are not variables, it's ok to join or union tables with duplicated column names. See below.
Is the error coming from the union or the join? Try running just the first sub-select, then just the second sub-select.
As a possible workaround, it looks like you could factor out the union of the two cards tables, and SELECT FROM bills JOIN cats JOIN suppliers JOIN (SELECT * from new_cards UNION SELECT * from sold_cards) cards WHERE ...
UNION merges duplicate rows (UNION ALL returns all rows from both sides). If you know you won't have duplicates, you could avoid the union altogether and select just the sum of two counts directly, ie select (select count(*) from ...joins...) + (select count(*) from ...joins...).
None of this answers why it would return an error.
I ran a quick test, which worked:
create table a (id int, a int, b int);
create table b (id int, a int, b int);
insert into a values (1,1,1), (2,2,2);
insert into b values (3,3,3);
select count(*) from ( (select * from a) union (select * from b) ) t;
+----------+
| count(*) |
+----------+
| 3 |
+----------+
1 row in set (0.00 sec)
select * from ( (select * from a) union (select * from b) ) t;
+------+------+------+
| id | a | b |
+------+------+------+
| 1 | 1 | 1 |
| 2 | 2 | 2 |
| 3 | 3 | 3 |
+------+------+------+
3 rows in set (0.00 sec)
select count(*) from a inner join b where a.a = b.a and b.a = a.a;
+----------+
| count(*) |
+----------+
| 0 |
+----------+
1 row in set (0.00 sec)
Oh, I see it -- the error is coming from the nested select temp tables.
When running the query, mysql must create a temporary table for each of the two inner selects. It's those temp tables that error out, because you can't create a table with two identically named columns.
If you equated the two Cat_ID's in the join condition instead of in the WHERE, mysql should recognize that they're identical and it should work; something like:
SELECT COUNT(*) FROM (
SELECT * FROM bills
JOIN cats USING (Cat_ID)
JOIN suppliers USING (Sup_ID)
JOIN sold_cards USING (Bill_ID, Sup_ID)
UNION
SELECT * ...
)
Or like Svea said, select a specific column like cats.Cat_ID to count. (And selecting just one column will run faster than selecting all)
select * from (select * from a join b) t;
ERROR 1060 (42S21): Duplicate column name 'id'
select * from (select * from a join b using (id, a, b)) t;
Empty set (0.00 sec)

How to delete a row in 3 tables with same query in My sql

delete from tbl_savedgroupmessage, tbl_savedusermessage, tbl_message where tbl_savedgroupmessage.msgid= tbl_savedusermessage.msgid= tbl_message.msgid= '876'
I tried this but it throws error
Try this one -
DELETE t1, t2, t3
FROM
tbl_savedgroupmessage t1
JOIN tbl_savedusermessage t2
ON t1.msgid = t2.msgid
JOIN tbl_message t3
ON t1.msgid = t3.msgid
WHERE
t3.msgid = '876'
Example:
CREATE TABLE table_a (
id INT(11) DEFAULT NULL
);
CREATE TABLE table_b (
id INT(11) DEFAULT NULL
);
INSERT INTO table_a VALUES
(2),
(3),
(1);
INSERT INTO table_b VALUES
(2),
(5),
(1);
DELETE t1, t2
FROM
table_a t1
JOIN table_b t2
ON t1.id = t2.id
WHERE
t1.id = 1;
SELECT * FROM table_a;
+------+
| id |
+------+
| 2 |
| 3 |
+------+
SELECT * FROM table_b;
+------+
| id |
+------+
| 2 |
| 5 |
+------+
You cannot delete from three tables in one query in that manner. delete is an operation that targets a single table.
delete from tbl_savedgroupmessage where msgid = '876';
delete from tbl_savedusermessage where msgid = '876';
delete from tbl_message where msgid = '876'
If there are constraints in place referencing one table to the other, you will have to change the order. If you need these all to fail or succeed together, put them in a transaction and roll back on the failure of any.
Edit: While true with ANSI compliant sql and in T-SQL, it is actually possible to delete from multiple tables in one statement in mysql. guess you learn something new every day.
You will have to join the tables together in order to delete it together. Also, add the columns you would like to delete.
for example:
delete tbl_savedgroupmessage.*, tbl_savedusermessage.*
from tbl_savedgroupmessage, tbl_savedusermessage
where tbl_savedgroupmessage.msgid = tbl_savedusermessage.msgid
and tbl_savedgroupmessage.msgid = '876'
You may use a joined DELETE command or delete the rows seperately.
DELETE FROM
tbl_message, tbl_savedgroupmessage, tbl_savedusermessage
LEFT JOIN
tbl_savedgroupmessage ON (tbl_message.msgid = tbl_savedgroupmessage.msgid)
LEFT JOIN
tbl_savedusermessage ON (tbl_message.msgid = tbl_savedusermessage.msgid)
WHERE
tbl_message.msgid = 876;