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

Posted

技术标签:

【中文标题】MySQL 分配在更新查询中仅匹配一次【英文标题】:MySQL Assign matches only once in an update query 【发布时间】:2015-12-04 08:01:29 【问题描述】:

我有两张表,一张包含参与者及其排名,另一张包含优惠券代码及其排名。我想为每个参与者分配一个具有正确等级的优惠券代码,但当然要确保每个优惠券代码只使用一次。

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

【问题讨论】:

为了确保凭证仅在您可以将UNIQUE KEY 添加到A.voucherid 时使用,但您将无法使用该查询更新所有行,因为它会尝试插入重复,整个更新将失败 【参考方案1】:

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

这个想法是使用一个计数器作为第二个比较变量,以确保将等级为 1 的凭证 1 分配给一个参与者,将等级 1 的凭证 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)之前执行,这会导致错误的结果。

【讨论】:

以上是关于MySQL 分配在更新查询中仅匹配一次的主要内容,如果未能解决你的问题,请参考以下文章

Mysql用户管理和权限分配

仅从日期时间字段(mysql)中提取日期并将其分配给 php 变量

MYSQL性能优化以及建议

使用 excel 公式或幂查询将主表中的小时数分配到参考表中的所有匹配值

如何在不使用游标的情况下一次将查询结果分配给多个变量?

### mysql系统结构_3_Mysql_Learning_Notes