从子表中删除数据

时间:2013-08-01 16:11:33

标签: sql postgresql foreign-keys sql-delete

我有两张桌子:

“客户”和“地址”。客户可以拥有多个地址,因此他们之间存在“n:m”关系。 出于这个原因,我还有“customer-addr”表。

这就是我的表格的样子:

                    +---------------+       
+-----------+       | customer_addr |       
| customers |       +---------------+       +-----------+
+-----------+       | id            |       | addresses |
| id        | <---> | cid           |       +-----------+
| name      |       | aid           | <---> | id        |
+-----------+       +---------------+       | address   |
                                            +-----------+

我需要更新所有客户数据,包括所有地址。出于这个原因,我首先考虑删除所有现有地址,然后更新客户表,之后,我创建了每个新地址。

我的问题:如何有效删除一位客户的所有现有地址? (我必须从2个表中删除行。)

我可以使用单一陈述吗? (没有级联方法,这太冒险了)

或者我可以使用2个语句,而不使用子选择吗?

最好的办法是什么?

请注意我正在使用postgresql

修改

我的整个数据库设计更加复杂,地址表不仅是来自“客户”的孩子,也来自“供应商”,“批量购买者”,...

每个地址只属于一个客户或一个供应商或一个批量购买者。 (没有地址被多个父母使用/没有地址共享)

永远的客户/供应商/ ..可以有多个地址。

出于这个原因,zebediah49编辑的解决方案将无效,因为它还会删除每个供应商/批量商/ ...的所有地址。

2 个答案:

答案 0 :(得分:2)

我会在 PostgreSQL 9.1或更高版本中使用writable CTE也称为数据修改CTE:

WITH del AS (
   DELETE FROM customer_addr
   WHERE  cid = $kill_this_cid
   RETURNING aid
   )
DELETE FROM addresses a
USING  (SELECT DISTINCT aid FROM del) d
WHERE  a.id = d.aid;

这应该是最快和最安全的。

如果在(cid, aid)UNIQUE定义了customer_addr,则您不需要DISTINCT步骤:

...
DELETE FROM addresses a
USING  del d
WHERE  a.id = d.aid;

答案 1 :(得分:1)

编辑:

得到了;这是更安全的,因为无论如何两个客户共享地址的风险:

DELETE FROM customer_addr WHERE cid = $TARGET_CID;
DELETE FROM addresses WHERE id NOT IN (SELECT aid FROM customer_addr);

首先,删除所有引用,然后删除所有未引用的地址。 请注意,您可以,例如,只执行第一步,并运行&#34;清理&#34;后来的第二步。


我建议两步交易:

DELETE FROM addresses WHERE id IN (SELECT ca.aid FROM customers c LEFT JOIN customer_addr ca ON ca.cid=c.id WHERE c.name='$NAME_TO_DELETE');
DELETE FROM customer_addr WHERE cid = (SELECT id FROM customers WHERE name='$NAME_TO_DELETE');

如果您已拥有客户ID(编辑:您这样做),您可以跳过大部分内容:

DELETE FROM addresses WHERE id IN (SELECT aid FROM customer_addr WHERE cid=$TARGET_CID);
DELETE FROM customer_addr WHERE cid = $TARGET_CID;

使用适当的交易BEGIN / END包裹,以确保您不会以不一致的状态结束,并且您应该设置。