tags:

views:

451

answers:

6

I have two tables: orders and orders_items. Both sharing the field orderID.

I want to delete all rows from both tables where orderID=500, but I need to do this in only one query. Is this possible?

+1  A: 

Could you use a stored function and call that?

And then inside your stored function you would have both DELETE queries. Then, when the stored function is called it will run as a transaction and you can make it return anything you like.

Evernoob
stored procedures are elusive to me. The don't like me :-(
The Disintegrator
+3  A: 

You can define the table with ON DELETE CASCADE. If you do that, you only have to delete on the order table. The entries in other tables using order_id as foreign key with that option enabled will be deleted automagically.

This example is taken from the MySQL manual:

CREATE TABLE parent(
    id INT NOT NULL,
    PRIMARY KEY (id)
) ENGINE=INNODB;

CREATE TABLE child(
    id INT, parent_id INT,
    INDEX par_ind (parent_id),
    FOREIGN KEY (parent_id) REFERENCES parent(id) ON DELETE CASCADE
) ENGINE=INNODB;

Note that the engine is InnoDB.

yeyeyerman
Sound ok. I'll try it. And come back.
The Disintegrator
It worked like a charm. Thanks.ALTER TABLE orders_items ADD FOREIGN KEY (orderID) REFERENCES orders(orderID) ON DELETE CASCADE
The Disintegrator
+5  A: 

Surely you can do that:

DELETE FROM `table1`, `table2` WHERE `orderId` = 500

see http://dev.mysql.com/doc/refman/5.0/en/delete.html

[EDIT:]

This is the whole trick:

DELETE FROM `orders`, `orders_items` 
  USING `orders` 
  INNER JOIN `orders_items` ON `orders`.`orderId` = `orders_items`.`orderId` 
  WHERE `orders`.`orderId`= 500

If orderId is a varchar, then change the statement to = '500'.

Residuum
#1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'where orderID=500' at line 1
The Disintegrator
+3  A: 

That depends on your database engine, but basically what you need sounds like you want one table referencing the other using a FOREIGN KEY with ON DELETE CASCADE option and then removal from the parent table will automatically remove corresponding rows from dependent tables.

Michael Krelin - hacker
I just wanted to write same thing :) Cascade is easiest thing to do.
Thinker
looking into it, thanks
The Disintegrator
+2  A: 

Here's a simply solution if you're using MySQL/PgSQL...

DELETE t1, t2 FROM table1 AS t1 
LEFT JOIN table2 AS t2 USING( orderID ) 
WHERE t1.orderID = 500;

Guaranteed to work like a charm!

Make sure to replace table1 and table2 with appropriate table names in your case.

I've used plenty of this query in my custom designed CMS - wherever I've wanted to avoid two distinct atomic queries. This is as good as a cascading delete and the query can be expanded to span over as many tables as you want.

Here's another example involving 3 tables:

DELETE t1, t2, t3 FROM table1 AS t1 
LEFT JOIN table2 AS t2 USING( orderID ) 
LEFT JOIN table3 AS t3 USING( orderID ) 
WHERE t1.orderID = 500;

Cheers, m^e

miCRoSCoPiC_eaRthLinG
Oh, nice. I'll keep it in mind.
The Disintegrator
+1  A: 

If you're using InnoDB (or a storage engine that supports them) you can use FOREIGN KEY constraints to delete the correspoding rows. This is one of the easiest/safest approach if you don't mind the slight performance impact of foreign keys. Note however that rows deleted because of constraints do not get triggers to fire.

Alternatively, you can use triggers. They work with any storage engine and they're usually easy enough to write. I like them but they're not very performant if you're deleting a large number of rows at once (several hundreds or thousands.)

CREATE TRIGGER ad_orders AFTER DELETE ON orders
FOR EACH ROW DELETE FROM orders_items WHERE orderID = OLD.orderID;

Finally, as suggested in a previous answer, you could use multi-table DELETE:

DELETE o, oi
FROM orders o
LEFT JOIN orders_items oi USING (orderID)
WHERE o.orderID = 500;
Josh Davis
thank you very much
The Disintegrator