我有两张桌子:
“客户”和“地址”。客户可以拥有多个地址,因此他们之间存在“n:m”关系。 出于这个原因,我还有“customer-addr”表。
这就是我的表格的样子:
+---------------+
+-----------+ | customer_addr |
| customers | +---------------+ +-----------+
+-----------+ | id | | addresses |
| id | <---> | cid | +-----------+
| name | | aid | <---> | id |
+-----------+ +---------------+ | address |
+-----------+
我需要更新所有客户数据,包括所有地址。出于这个原因,我首先考虑删除所有现有地址,然后更新客户表,之后,我创建了每个新地址。
我的问题:如何有效删除一位客户的所有现有地址? (我必须从2个表中删除行。)
我可以使用单一陈述吗? (没有级联方法,这太冒险了)
或者我可以使用2个语句,而不使用子选择吗?
最好的办法是什么?
请注意我正在使用postgresql
修改
我的整个数据库设计更加复杂,地址表不仅是来自“客户”的孩子,也来自“供应商”,“批量购买者”,...
每个地址只属于一个客户或一个供应商或一个批量购买者。 (没有地址被多个父母使用/没有地址共享)
永远的客户/供应商/ ..可以有多个地址。
出于这个原因,zebediah49编辑的解决方案将无效,因为它还会删除每个供应商/批量商/ ...的所有地址。
答案 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
包裹,以确保您不会以不一致的状态结束,并且您应该设置。