我有一个像这样的表客户:
CREATE TABLE tbl_customer (
id INTEGER,
name VARCHAR(16),
voucher VARCHAR(16)
);
和这样的凭证表:
CREATE TABLE tbl_voucher (
id INTEGER,
code VARCHAR(16)
);
现在假设customer表始终包含填写了id和name的行,但是需要定期从tbl_voucher
表插入凭证。
重要提示:每张优惠券只能分配给一个特定客户(即必须是唯一的)
我写了一个这样的查询:
UPDATE tbl_customer
SET voucher = (
SELECT code
FROM tbl_voucher
WHERE code NOT IN (
SELECT voucher
FROM tbl_customer
WHERE voucher IS NOT NULL
)
LIMIT 1
)
WHERE voucher IS NULL;
然而,这不能按预期工作,因为查找未使用的凭证的部分会执行一次,然后凭证会应用于每个客户。
关于如何在不使用循环等编程结构的情况下解决这个问题的任何想法?
此外,一些示例数据让您可以想象我想要发生的事情:
INSERT INTO tbl_customer VALUES (1, 'Sara', 'ABC');
INSERT INTO tbl_customer VALUES (1, 'Simon', 'DEF');
INSERT INTO tbl_customer VALUES (1, 'Andy', NULL);
INSERT INTO tbl_customer VALUES (1, 'Alice', NULL);
INSERT INTO tbl_voucher VALUES (1, 'ABC');
INSERT INTO tbl_voucher VALUES (2, 'LOL');
INSERT INTO tbl_voucher VALUES (3, 'ZZZ');
INSERT INTO tbl_voucher VALUES (4, 'BBB');
INSERT INTO tbl_voucher VALUES (5, 'CCC');
执行完所需的查询后,我希望Andy
能够获得凭证LOL
,而Alice
应该获得ZZZ
答案 0 :(得分:2)
我猜这是MySQL。答案是,这是一种痛苦。以下内容分配select
:
select c.*, v.voucher
from (select c.*, (@rnc := @rnc + 1) as rn
from tbl_customer c cross join
(select @rnc := 0) params
where c.voucher is null
) c join
(select v.*, (@rnv := @rnv + 1) as rn
from tbl_vouchers v cross join
(select @rnv := 0) params
where not exists (select 1 from tbl_customers c where c.voucher = v.voucher)
) v
on c.rn = v.rn;
您现在可以将其用于update
:
update tbl_customer c join
(select c.*, v.voucher
from (select c.*, (@rnc := @rnc + 1) as rn
from tbl_customer c cross join
(select @rnc := 0) params
where c.voucher is null
) c join
(select v.*, (@rnv := @rnv + 1) as rn
from tbl_vouchers v cross join
(select @rnv := 0) params
where not exists (select 1 from tbl_customers c where c.voucher = v.voucher)
) v
on c.rn = v.rn
) cv
on c.id = cv.id
set c.voucher = cv.voucher;