【问题标题】:Best way to write this query编写此查询的最佳方式
【发布时间】:2010-01-05 08:47:14
【问题描述】:

我有两个 MySql 表,如下所示,数据显示:

CREATE TABLE `A` (
`id` int(12) NOT NULL AUTO_INCREMENT,
`status` varchar(50) DEFAULT NULL,
`another_field` varchar(50) DEFAULT NULL
)

INSERT INTO `A` VALUES ('1', null, 'a');
INSERT INTO `A` VALUES ('2', null, 'b');
INSERT INTO `A` VALUES ('3', null, 'c');


CREATE TABLE `B` (
`id` int(12) NOT NULL AUTO_INCREMENT,
`status` varchar(50) DEFAULT NULL,
`tableA_id` int(12) DEFAULT NULL,
PRIMARY KEY (`id`)
)

INSERT INTO `B` VALUES ('1', 'aa', '1');
INSERT INTO `B` VALUES ('2', 'aa', '1');
INSERT INTO `B` VALUES ('3', 'aa', '2');
INSERT INTO `B` VALUES ('4', 'aa', '3');
INSERT INTO `B` VALUES ('5', 'bb', '3');

我想知道当 A.id = B.tableA_id 使用单个查询时,如果所有 B.status 都相同,是否可以更新 A.status?

这就是我希望我的表 A 的样子:

('1', 'aa', 'a') - 状态更新为 'aa' 因为 B.id 1 和 2 具有相同的状态和相同的 B.tableA_id 值。
('2', 'aa', 'b') - 状态更新为 'aa',因为 B.id 3 具有相同的状态。
('3', null, 'c') - 这不会更新,因为 B.id 4 和 5 具有不同的状态和相同的 table2.table1_id 值。

谢谢

【问题讨论】:

  • 您的查询中缺少几个分号和表 a 上的主键定义
  • 感谢指点..请忽略SQL语句中的任何语法错误。
  • bzabhi,Anax 是对的。由于缺少 PRIMARY KEY 子句(AUTO_INCREMENT 必须具有该子句),因此表定义也不会在 MySQL 上运行。下次请检查您的脚本,让帮助更愉快。

标签: sql mysql


【解决方案1】:
UPDATE A
SET    status = COALESCE((
           SELECT MAX(B.status)
           FROM   B
           WHERE  B.tableA_id = A.id
           HAVING MAX(B.status) = MIN(B.status)
       ), A.status)

(注意:我添加了一个更正,您需要COALESCE(..., A.status),否则状态将设置为NULL,以防B中有多个状态

【讨论】:

    【解决方案2】:

    不确定 MySql 但在 MSSQL 中您可以编写如下内容:

    更新 A SET A.Status = 'aa' 从 A.id = B.tableA_id 上的 A INNER JOIN B WHERE b.status = 'aa'

    在 MySQL 中应该是类似的,但如果语言支持更新时的连接,我不是。但我仍然希望它有所帮助。

    【讨论】:

    • 这种语法在 MySQL 中有效,但是这个查询没有给出正确的结果。它将设置 A(3).status = 'aa',即使 B(3) 有两个不同的状态值:'aa' 和 'bb'。
    【解决方案3】:
    UPDATE a SET status = 
        (
            SELECT status FROM b WHERE tableA_id = a.id LIMIT 0,1
        )
    WHERE id IN
        (
            SELECT tableA_id FROM b
            GROUP BY tableA_id
            HAVING COUNT(DISTINCT status) = 1
        )
    

    更新:罗兰是对的;我已经更新了查询,现在它产生了正确的结果。

    【讨论】:

    • 这个查询不正确。分配中使用的子查询可以并且将返回一个集合。您需要添加一个聚合函数,如 MIN(status) 或 MAX(status),添加一个不同的关键字(DISTINCT 状态)或在 where 之后添加 GROUP BY 状态。
    • 我运行了一些测试,查询的行为正常。您能否提供一个特定的数据集,使查询行为异常?
    • Anax,回想起来,确实你的子查询没有返回一个集合。但这仅仅是因为您还有另一个问题:第一个子查询的 WHERE 子句:WHERE b.tableA_id = id 是错误的。对id 的引用应该绑定到A.id,但它不是——因为它没有别名,它引用B.id。所以意外地,它总是最多产生一行。如果您更正查询并运行它,您将收到 ERROR 1242 (21000): Subquery return more than 1 row。
    • 我确实尝试了你的建议;每次我得到正确的结果。首先,我尝试通过将字符串“a_”放在每个字段前面来重命名所有表字段,并且查询运行没有问题。然后我恢复到原始字段名称,并通过运行查询“UPDATE a as NewTable SET NewTable.status = (SELECT status FROM b WHERE b.tableA_id = NewTable.id) WHERE NewTable.id IN (SELECT tableA_id FROM b GROUP BY tableA_id HAVING COUNT(DISTINCT status) = 1)",它再次运行没有错误。我正在使用 MySQL 版本 5.1.39CE
    • Anax,我不知道你为什么不能重现结果。我可以。但是这样看。让我们从 OP 获取数据。好吧,首先,评估您的 WHERE 子查询,这会产生 (1,2),因为 b.id=3 的状态有 2 个不同的值。现在,扫描 A.id 为 1 和 2 的行,并为它们中的每一个评估 SET 子句中的子查询。好吧,对于 A.id = 1,您立即从 B (B.id's: 1,2) 获得 2 行。这是一个集合,在子查询中无效。如果您想进一步讨论,请随时发送电子邮件至:roland.bouman@gmail.com。干杯!
    【解决方案4】:
    CREATE TABLE `A` (
    `id` int(12) NOT NULL AUTO_INCREMENT,
    `status` varchar(50) DEFAULT NULL,
    `another_field` varchar(50) DEFAULT NULL
    )
    
    INSERT INTO `A` VALUES ('1', null, 'a');
    INSERT INTO `A` VALUES ('2', null, 'b');
    INSERT INTO `A` VALUES ('3', null, 'c');
    
    
    CREATE TABLE `B` (
    `id` int(12) NOT NULL AUTO_INCREMENT,
    `status` varchar(50) DEFAULT NULL,
    `tableA_id` int(12) DEFAULT NULL,
    PRIMARY KEY (`id`)
    )
    
    INSERT INTO `B` VALUES ('1', 'aa', '1');
    INSERT INTO `B` VALUES ('2', 'aa', '1');
    INSERT INTO `B` VALUES ('3', 'aa', '2');
    INSERT INTO `B` VALUES ('4', 'aa', '3');
    INSERT INTO `B` VALUES ('5', 'bb', '3');
    

    【讨论】:

      猜你喜欢
      • 2014-04-15
      • 1970-01-01
      • 2023-04-01
      • 2018-08-30
      • 2013-06-27
      • 1970-01-01
      • 2015-04-05
      • 2020-07-09
      • 1970-01-01
      相关资源
      最近更新 更多