2015-09-08 45 views
3

我有两个表,一个带有参与者及其排名,另一个带有优惠券代码及其排名。我想为每位参与者分配正确等级的优惠券代码,但确保每张优惠券代码仅使用一次,当然。MySQL在更新查询中仅分配匹配一次

Table A:        Table B: 
pid | name | rank | voucherid  voucherid | rank | code | used 
1 | Max | 10 | null    1   | 10 | AAA | 0 
2 | Joe | 20 | null    2   | 10 | BBB | 0 
3 | Eva | 10 | null    3   | 20 | CCC | 0 
            4   | 20 | DDD | 0 

我正在寻找一个更新查询产生这样的结果:

Table A: 
pid | name | rank | voucherid 
1 | Max | 10 | 1 
2 | Joe | 20 | 3 
3 | Eva | 10 | 2 

下不起作用,因为它赋予了相同的优惠券到多个参与者:

UPDATE A 
JOIN B ON A.`rank` = B.`rank` 
SET A.`voucherid` = B.`voucherid` 
WHERE 
    A.`voucherid` IS NULL AND 
    B.`used` = 0 
; 
- 
Result: 
Table A: 
pid | name | rank | voucherid 
1 | Max | 10 | 1 
2 | Joe | 20 | 3 
3 | Eva | 10 | 1 !!! 

之后当然我会更新优惠券表B,将used列设置为1

+0

要确保凭证只有在您可以向'A.voucherid'添加'UNIQUE KEY'时才会使用,但是您将无法使用该查询更新所有行,因为它会尝试插入重复项,整个更新将失败 –

回答

0

我想我使用user variables找到答案,这就是为什么我回答我自己的问题。

这个想法是使用一个计数器作为第二个比较变量,以确保具有rank1的凭证1被分配给一个参与者,并且具有rank1的凭证2被分配给另一个参与者。

MySQL查询非常麻烦。这就是为什么我可能使用PHP来解决问题。但是,我想分享它,至少:

UPDATE `A` AS ua 
JOIN (

    SELECT 
    ta.`participantid`, ta.`rank`, 
    (@ca := IF(@pa = ta.`rank`, @ca + 1, 0)) AS `counter`, 
    @pa := ta.`rank` 
    FROM `A` AS ta, (SELECT @ca := 0, @pa := 0) AS ia 
    WHERE 
    ta.`voucherid` IS NULL 
    ORDER BY `rank` ASC 

) AS a ON a.`pid` = ua.`pid` 
JOIN (

    SELECT 
    tb.`voucherid`, tb.`rank`, 
    (@cb := IF(@pb = tb.`rank`, @cb + 1, 0)) AS `counter`, 
    @pb := tb.`rank` 
    FROM `B` AS tb, (SELECT @cb := 0, @pb := 0) AS ib 
    WHERE 
    tb.`used` = 0 
    ORDER BY `rank` ASC 

) AS b ON (b.`rank` = a.`rank` AND b.`counter` = a.`counter`) 
JOIN `B` AS ub ON ub.`voucherid` = b.`voucherid` 
SET 
    ua.`voucherid` = b.`voucherid`, 
    ub.`used` = 1 
; 

它工作在测试情况下,我准备,但根据MySQL documentation你可以不依赖评价为表现的顺序。因此@pa := ta.rank可能会在IF(@pa = ta.rank)之前执行,这会导致错误的结果。