【问题标题】:SQL: Reference Column Value in Subquery and Vice VersaSQL:在子查询中引用列值,反之亦然
【发布时间】:2014-05-11 10:15:52
【问题描述】:

假设我正在处理一个看起来像这样的查询:

 update user as u 
   set u.city = (
    select min(c1.id) 
       from (
         select c1.id 
           from city c1 
          where c1.name = (
            select c2.name 
              from city c2 where c2.id = u.city)) as duplicates);

这意味着对我的用户表中的城市列表进行重复数据删除,以使城市表中所有共享相同城市名称的 id 的城市 id 最小。因此进行了重复数据删除。但是,我收到此错误:

ERROR 1054 (42S22): Unknown column 'u.city' in 'where clause'

我的用户表确实有一个城市列,即

mysql> describe user;
+----------------------------+--------------+------+-----+---------+----------------+
| Field                      | Type         | Null | Key | Default | Extra          |
+----------------------------+--------------+------+-----+---------+----------------+
| id                         | bigint(20)   | NO   | PRI | NULL    | auto_increment |
| first_name                 | varchar(64)  | YES  |     | NULL    |                |
| last_name                  | varchar(64)  | YES  |     | NULL    |                |
...
| city                       | bigint(20)   | YES  | MUL | NULL    |                |
...
+----------------------------+--------------+------+-----+---------+----------------+
36 rows in set (0.00 sec)

所以我看到关于这个查询的两个有趣的事情,用户表城市列值(u.city)在子查询中被引用,城市表中的城市id被用于中间查询,(select min( c1.id))。我该如何进行这项工作?

【问题讨论】:

  • 在编写子查询时,请考虑范围以及如何处理查询。 IE:子查询在外部查询之前处理,因此子查询中依赖于外部查询的任何内容都将失败。你必须转变你的想法,从里到外写查询,而不是从外到里。
  • 你可以按 id 排序第二个查询并使用 LIMIT 只返回一行

标签: mysql sql join subquery where


【解决方案1】:

我认为使用显式 joins 而不是嵌套查询更容易编写这样的查询:

update user u join
       city c
       on u.city = c.city join
       (select name, min(id) as minid
        from city
        group by name
       ) cmin
       on cmin.name = c.name
    set u.city = cmin.minid;

MySQL 似乎也对关联引用的嵌套深度有一个限制,尽管我在任何地方都没有发现这个限制。

【讨论】:

  • 我相信你可以嵌套任意深,但是关联引用的范围只是一层。这是(我相信)两次嵌套查询绕过 MySQL 的限制的原因,即不能从也引用同一个表的查询中更新表。
  • 最后,我创建了一个临时表来保存要删除的 ids。像create temporary table city_id_deduplication_map ( city_id bigint(20), canonical_id bigint(20), unique(city_id) ); 这样的东西然后加入/更新了这张桌子。让生活更简单,SQL 更容易查看。感谢您的回答。同样显然 mysql 不能很好地比较空值,所以相等性检查 u.city = c.city 需要是 u.city = c.city or (u.city is null and c.city is null)
  • @MatBailie 。 . .我也相信。不幸的是,我找不到文档参考(最适合dev.mysql.com/doc/refman/5.7/en/correlated-subqueries.html)。
【解决方案2】:

可能的解决方案:-

UPDATE user 
INNER JOIN
(             
    SELECT u.city, MIN(c1.id) AS min_city
    FROM user u
    INNER JOIN city c2 ON c2.id = u.city
    INNER JOIN city.c1 ON c1.name = c2.name
    GROUP BY u.city
) sub1
ON u.city = sub1.city
SET u.city = sub1.min_city

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-02-05
    • 1970-01-01
    • 1970-01-01
    • 2021-12-21
    • 2013-07-08
    • 2012-04-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多