MySQL在更新查询中仅匹配一次匹配

时间:2015-09-08 14:59:44

标签: mysql join

我有两张桌子,一张是参与者和他们的排名,另一张是凭证代码及其排名。我想为每个参与者分配一个具有正确排名的优惠券代码,但当然要确保每个优惠券代码只使用一次。

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

1 个答案:

答案 0 :(得分:0)

我认为我使用user variables找到了答案,这就是我回答自己问题的原因。

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

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)之前执行,这会导致错误的结果。