How to delete all rows from a mysql table if values of two columns are equal
Example Table
invoice_id| item_id | name | invoiced_qty | received_qty
---------------------------------------------------------
| 1 | 1 | item1 | 3 | 2
| 2 | 2 | item2 | 5 | 5
| 3 | 1 | item3 | 4 | 3
| 4 | 2 | item4 | 2 | 2
| 5 | 1 | item5 | 5 | 5
After deleting table needs to retains
invoice_id| item_id | name | invoiced_qty | received_qty
---------------------------------------------------------
| 1 | 1 | item1 | 3 | 2
| 3 | 1 | item3 | 4 | 3
The select query which i created is
SELECT * FROM table1 A
INNER JOIN table1 B ON A.item_id = B.item_id
AND A.invoice_id = B.invoice_id
AND A.invoiced_qty = B.received_qty
Thanks
Why not just SQL Fiddle:
DELETE FROM table1
WHERE invoiced_qty = received_qty
Your edit does not change anything. He is the SQL Fiddle demonstrating your SELECT query. According to your sample data A.invoice_id will never equal B.invoice_id. So you will not get any results.
Try this :
DELETE FROM table1 A
INNER JOIN table1 B ON A.item_id = B.item_id
WHERE A.invoiced_qty = B.received_qty
You could simply wrap your select statement and select values to be deleted by id, like this:
DELETE FROM table1
WHERE item_id IN (SELECT item_id FROM table1 A
INNER JOIN table1 B ON A.item_id = B.item_id
AND A.invoice_id = B.invoice_id
AND A.invoiced_qty = B.received_qty)
however you should accept answer by Linger as it is more straightforward solution, mine was to indicate that if you have something selected usually you can wrap and delete.
Related
Imagine I have a table like this with a many to one relationship
Table1
id | name
1 | as
2 | df
3 | gh
and
id | othercontents | table1relationship
1 | qw | 1
2 | er | 2
3 | ty | 3
4 | ui | 3
if I run a select query on Table1 with a left join for Table2 but limit it to 3 results I will get 3 rows returned
1 - as - qw
2 - df - er
3 - gh - ty
however I want
1 - as - qw
2 - df - er
3 - gh - [ty, ui]
Now, currently I am selecting it as normal and then putting othercontents into an array myself to turn my rows into how I want them, but the problem remains that I can not return all the rows I want.
Logically, I suppose I want to limit to X unique table1.id's rather than limiting to just X rows, but I do not know a way to implement this logic if it is even possible.
Ofcourse this is easy if I select everything in the database and then sort it in PHP but this is too intensive and I don't want to select 20,000 rows just to get ~10 rows. I suppose a hacky way around this would be to select 30 rows and then do my own sorting and return the 10 as I want them but it still seems silly to me to select more than I need.
Perhaps worth mentioning but I am using Symfony3 w/ Doctrine and using query builder. But I am not asking for copy/paste answer to my problem rather just a push in the direction so I can work on my implementation.
Thanks
Here is a query that will give you the result ( if i understand you correct).
SELECT t1.id,t1.name,
CONCAT( IF(sum(1)>1,'[',''), GROUP_CONCAT(t2.othercontents), IF(sum(1)>1,']','')) AS name2
FROM (
SELECT *
FROM table1
LIMIT 3
) as t1
LEFT JOIN table2 t2 on t2.table1relationship = t1.id
GROUP BY t2.table1relationship;
sample
mysql> SELECT * from table1;
+----+------+
| id | name |
+----+------+
| 1 | as |
| 2 | df |
| 3 | gh |
+----+------+
3 rows in set (0,00 sec)
mysql> SELECT * from table2;
+----+---------------+--------------------+
| id | othercontents | table1relationship |
+----+---------------+--------------------+
| 1 | qw | 1 |
| 2 | er | 2 |
| 3 | ty | 3 |
| 4 | ui | 3 |
+----+---------------+--------------------+
4 rows in set (0,00 sec)
result
mysql> SELECT t1.id,t1.name,
-> CONCAT( IF(sum(1)>1,'[',''), GROUP_CONCAT(t2.othercontents), IF(sum(1)>1,']','')) AS name2
-> FROM (
-> SELECT *
-> FROM table1
-> LIMIT 3
-> ) as t1
-> LEFT JOIN table2 t2 on t2.table1relationship = t1.id
-> GROUP BY t2.table1relationship;
+----+------+---------+
| id | name | name2 |
+----+------+---------+
| 1 | as | qw |
| 2 | df | er |
| 3 | gh | [ui,ty] |
+----+------+---------+
3 rows in set (0,00 sec)
mysql>
I have two tables:
// table1 // table2
+----+------+---------+ +----+------+
| id | col1 | user_id | | id | col2 |
+----+------+---------+ +----+------+
| 1 | a | 100001 | | 1 | a |
| 2 | b | 100002 | | 2 | b |
| 3 | c | 100003 | | 3 | c |
+----+------+---------+ | 4 | a |
| 5 | a |
| 6 | c |
+----+------+
Also I have a variable named $user_id. Now I want to delete all row in the table2 where col2='a', But I need to check table1.user_id = $user_id (in this case $user_id = '100001' ) in the table1 before deleting.
How can I write a correct syntax query with this concept:
IF table1.user_id = $user_id where table1.col1 = 'a' then
delete from table2 where col2 = 'a'
I can do that using PHP and MySQL using two separated query. But I want to do that with one query, is it possible?
You can use JOIN to do the delete operation something as
delete t2 from table2 t2
join table1 t1 on t2.col2 = t1.col1
where
t2.col2 = 'a'
and t1.user_id = '100001'
I have 2 tables
table A
tag_id | Tag_name
1 | tg1
2 | tg2
3 | tg3
4 | tg4
table B
id | name |tag_id
1 | avq | 1,2,4
2 | bdq | 2
3 | abc | 3,2
4 | vdf | 1,4
5 | zxc | 3
I want to inner join both tables and get its count using tag_id in the following format
`tg1=> 2,tg2=> 3,tg3=> 2,tg4=> 2`
How is it possible in a single MySQL query?
The best option is to normalize the 2nd table and create an association table for storing the tag id and the id of the 2nd table. In the meanwhile the following should do the job but for long run you need to normalize the table else more problems will happen in future
select
t1.Tag_name, count(*) as total
from tableA t1
join tableB t2 on find_in_set(t1.tag_id,t2.tag_id) > 0
group by t1.tag_id ;
You need to create relation table. For example:
Tag table:
+----+----------+
| id | name |
+----+----------+
| 1 | Tag name |
+----+----------+
| 2 | Tag 2 |
+----+----------+
B Table:
+----+-----------+
| id | title |
+----+-----------+
| 1 | Any title |
+----+-----------+
Reference table ex. :
+------+--------+
| b_id | tag_id |
+------+--------+
| 1 | 1 |
+------+--------+
| 1 | 2 |
+------+--------+
In your reference table you put many tags for one B element. In this example you see two tags assigned by reference to b_id = 1
select tag_name, count(position)
from (
select a.tag_name, FIND_IN_SET(a.tag_id,b.tag_id) as position
from a,b
) as tmpTB
where position !=0
group by tag_name
I have a query to write and I am absolutely stumped on how to do it. Here's my situation, I am trying to provide a particular product_ID, then match all of the other product_IDs in the database that have at least the same intDescription_detail_IDs as the provided product_ID.
The relevant tables look like this:
tblproducts
=========================
product_ID | product_name
=========================
| 1 | dresser |
| 2 | bookcase |
| 3 | table |
| 4 | chair |
=========================
tbldescriptions
=========================================================================
|description_ID| intDescription_product_ID | intDescription_detail_ID |
=========================================================================
| 1 | 1 | 1 |
| 2 | 1 | 2 |
| 4 | 2 | 1 |
| 5 | 2 | 2 |
| 6 | 2 | 6 |
| 7 | 3 | 1 |
| 8 | 3 | 3 |
| 9 | 3 | 4 |
| 10 | 4 | 1 |
| 11 | 4 | 2 |
| 12 | 4 | 7 |
As an example, if I provided the product_ID "1", then I would like to return all of the product_IDs that at least have intDescription_detail_ID 1 and 2.
So, the product_IDs that should be returned are 1, 2, and 4, because all of these products have the intDescription_detail_ID of 1 and 2 among their details.
I am highly confused about how to write a query like this, so any help is greatly appreciated!
I should warn you by saying that I may have made a silly mistake here...
DROP TABLE IF EXISTS products;
CREATE TABLE products(product_ID INT NOT NULL AUTO_INCREMENT PRIMARY KEY,product_name VARCHAR(20) NOT NULL UNIQUE);
INSERT INTO products VALUES
(1,'dresser'),
(2,'bookcase'),
(3,'table'),
(4,'chair');
DROP TABLE IF EXISTS product_detail;
CREATE TABLE product_detail
(product_id INT NOT NULL
,detail_id INT NOT NULL
,PRIMARY KEY(product_id,detail_id)
);
INSERT INTO product_detail VALUES
(1,1),
(1,2),
(2,1),
(2,2),
(2,6),
(3,1),
(3,3),
(3,4),
(4,1),
(4,2),
(4,7);
SELECT DISTINCT c.product_id
FROM product_detail a
JOIN product_detail b
ON b.product_id = a.product_id
AND b.detail_id <> a.detail_id
JOIN product_detail c
ON c.product_id <> a.product_id
AND c.detail_id = a.detail_id
JOIN product_detail d
ON d.product_id = c.product_id
AND d.detail_id = b.detail_id
WHERE a.product_id = 1;
+------------+
| product_id |
+------------+
| 2 |
| 4 |
+------------+
Alternative to #Strawberry’s suggestion with JOINs this can also be done using HAVING for filtering products that have (at least) the same number of rows with the same intDescription_detail_IDs as the product the search is done for:
SELECT intDescription_product_ID
FROM tbldescriptions t1
WHERE intDescription_detail_ID IN (
SELECT intDescription_detail_ID
FROM tbldescriptions t2
WHERE t2.intDescription_product_ID = 1
)
GROUP BY intDescription_product_ID
HAVING count(*) >= (
SELECT count(intDescription_detail_ID)
FROM tbldescriptions t3
WHERE t3.intDescription_product_ID = 1
)
http://sqlfiddle.com/#!2/ce698/2
One should keep in mind though that HAVING is applied last, so that will select all products with at least one matching intDescription_detail_ID first, and filter the results based on the actual count afterwards – so depending on the size and characteristic of your data set that might not be the best performing solution.
I have a table with an auto increment key id, item_no can be either one or two rows in a row (so they always have consecutive ids) that share the same ref but have different right/left (but technically item_no can be repeated multiple times throughout the table but that's not an issue), and description will sometimes be the same on the consecutive rows but sometimes different:
id | item_no | description | right\left | ref
1 | 1 | a1 | right | aaa
2 | 1 | a1 | left | aaa
3 | 2 | b1 | right | bbb
4 | 3 | c1 | right | ccc
5 | 3 | c2 | left | ccc
6 | 4 | d1 | right | ddd
7 | 4 | d1 | left | ddd
My issue is that I need item_no to append a -r or -l on to its value if the description of its 'matching' row is different.
So the result I am looking for is:
id | item_no | description | right\left | ref
1 | 1 | a1 | right | aaa
2 | 1 | a1 | left | aaa
3 | 2 | b1 | right | bbb
4 | 3-r | c1 | right | ccc
5 | 3-l | c2 | left | ccc
6 | 4 | d1 | right | ddd
7 | 4 | d1 | left | ddd
I am exporting the table to a csv but am not using much php, just a mysql statement and then looping out the results, is this possible within the mysql statement or will I have to rely on a php loop?
I would use this:
update
items inner join
(select item_no from items
group by item_no
having count(distinct description)>1) dup
on items.item_no=dup.item_no
set
items.item_no=concat(items.item_no, '-', substr(rightleft, 1,1))
If rows are always consecutive, you could also use this:
update
items i1 inner join items i2
on (i1.id=i2.id+1 or i1.id=i2.id-1)
and (i1.item_no=i2.item_no)
and (i1.description<>i2.description)
set i1.item_no=concat(i1.item_no, '-', substr(i1.rightleft, 1,1))
EDIT: if rows are always consecutive, and you just need a select and not an update, you could use this:
select
i1.id,
case when i1.description=i2.description or i2.id is null then i1.item_no else
concat(i1.item_no, '-', substr(i1.rightleft, 1,1)) end,
i1.description, i1.rightleft, i1.ref
from
items i1 left join items i2
on (i1.id=i2.id+1 or i1.id=i2.id-1) and (i1.item_no=i2.item_no)
order by i1.id
Try this:
SELECT
id,
CASE RightLeft
WHEN 'right' THEN CONCAT(item_no, '-r' )
WHEN 'left' THEN CONCAT(item_no, '-l' )
END AS item_no,
DESCRIPTION,
Rightleft,
ref
FROM Items
WHERE item_no IN
(
SELECT i1.item_no
FROM items i1
GROUP BY i1.item_no
HAVING(COUNT(DISTINCT description)) > 1);
SQL Fiddle Demo
This will give you:
| ID | ITEM_NO | DESCRIPTION | RIGHTLEFT | REF |
------------------------------------------------
| 4 | 3-r | c1 | right | ccc |
| 5 | 3-l | c2 | left | ccc |
I would rely on a PHP loop if you're using mysql, if you were using Oracle or SQL server then you could program a stored procedure.
You script should look something like this:
$dbh = new PDO('mysql:host='.DATABASE_HOST.';dbname='.DATABASE_NAME, DATABASE_USER, DATABASE_PASSWORD);
$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$data = $dbh->query("SELECT * FROM ExampleTable");
$dbh->beginTransaction();
foreach($data as $row)
{
$append = $row["right\left"] == "left" ? $row["item_no"]."-l" : $row["item_no"]."-r";
$stmnt = $dbh->prepare("UPDATE ExampleTable SET item_no = :item WHERE id = :id");
$stmnt->execute(array(":item" => $append,":id" => $row["id"]));
}
// Do some exception handling if something goes wrong you can allways do a rollback
// With PDO $dbh->rollBack();
$dbh->commit();
$dbh = null;
Something like this
UPDATE [dbo].[maTable] SET [item_no] = [item_no]+'r' WHERE not distinct [description] from [dbo].[maTable]
Should add an 'r' in the registration line where [description] is not identical (coded for SQL Server)