使用子查询更新多行

时间:2015-08-28 13:50:39

标签: mysql sql

我在MySQL上遇到SQL请求的问题。我想在已经有数据(生产)的表中填写一个字段。我必须有一些关节来填充数据,但是当我执行查询时出现这个错误:

Error Code: 1242. Subquery returns more than 1 row

我知道这是因为我的子查询中有多个结果,但我必须将这些结果放到我的表中。我的问题:

UPDATE table1
SET application_id = (
    SELECT appid FROM (
        SELECT t2.application_id AS appid
        FROM table2 t2
        INNER JOIN table3 t3 ON t3.license_id = t2.licenseid
        INNER JOIN table1 t1 ON t1.datetime = t3.datetime
        WHERE t1.customer_id = t3.customer_id
        ORDER BY t1.datetime DESC
    ) AS app
)
ORDER BY datetime DESC;

我尝试使用嵌套子查询而不是关节,但我还有另一个问题:

Error Code: 1093. You can't specify target table 'table1' for update in FROM clause

我的查询:

UPDATE table1
SET application_id = (
    SELECT t2.application_id
    FROM table2 t2
    WHERE t2.licenseid IN (
        SELECT t3.license_id
        FROM table3 t3
        WHERE t3.datetime IN (
            SELECT t1.datetime
            FROM table1 t1
            WHERE t1.customer_id IN (
                SELECT t3.customer_id
                FROM table3 t3
            )
            ORDER BY t1.datetime DESC
        )
    )
)
ORDER BY datetime DESC 

您有什么建议可以让它发挥作用吗?我想到了一个存储过程,但我想知道是否可以不使用它。

编辑:

我通过存储过程改变了我想要的结果。它工作正常,但当我用生产数据(~90.000行)测试它时,它停在第1144行。我不知道为什么,下一行没有错,我有我需要的所有数据...是否有SQL中REPEAT循环的限制?这是我的存储过程:

DELIMITER ;;
CREATE PROCEDURE sp1(OUT app_id VARCHAR(36), IN reporting_id VARCHAR(36))
BEGIN
    SELECT t1.application_id
    INTO app_id
    FROM table1 t1
    INNER JOIN table2 t2 ON t2.license_id = t1.licenseid
    INNER JOIN table3 t3 ON t3.datetime = t2.datetime
    WHERE t3.customer_id = t3.customer_id
      AND t3.id = reporting_id;
END ;;
DELIMITER ;

DELIMITER ;;
CREATE PROCEDURE sp2(OUT app_id VARCHAR(36), IN reporting_id VARCHAR(36))
BEGIN
    SELECT t1.application_id
    INTO app_id
    FROM table1 t1
    INNER JOIN table4 t4 ON t4.license_id = t1.licenseid
    INNER JOIN table3 t3ON t3.datetime = t4.datetime
    WHERE t3.customer_id = t4.customer_id
      AND t3.id = reporting_id;
END ;;
DELIMITER ;

DELIMITER ;;
CREATE PROCEDURE sp3()
BEGIN

DECLARE done INT DEFAULT 0;
DECLARE reporting_id VARCHAR(36);
DECLARE application_id VARCHAR(36);
DECLARE cur1 CURSOR FOR SELECT id FROM table3 ORDER BY datetime DESC;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
DECLARE EXIT HANDLER FOR SQLEXCEPTION ROLLBACK;

OPEN cur1;

REPEAT
    FETCH cur1 INTO reporting_id;
    IF NOT done THEN
        CALL sp1(application_id, reporting_id);

        IF (application_id IS NULL) THEN
            CALL sp2(application_id, reporting_id);
        END IF;
        IF (application_id IS NOT NULL) THEN
            START TRANSACTION;
                UPDATE table3
                SET application_id = application_id
                WHERE id = reporting_id;
            COMMIT;
        END IF;
        SET application_id = NULL;
    END IF;
UNTIL done END REPEAT;

CLOSE cur1;

END ;;
DELIMITER ;

CALL sp3();

也许我做错了?没有结果可以帮助我找到问题。

2 个答案:

答案 0 :(得分:1)

您当前的查询正在尝试更新table1中的每一行,以在table2中拥有每个值。这是不允许的,而你可能想要的是table1中的每一行都有来自table2的相应值

UPDATE table1 t1
INNER JOIN table3 t3 ON t1.datetime = t3.datetime
AND t1.customer_id = t3.customer_id
INNER JOIN table2 t2 ON t3.license_id = t2.licenseid
SET application_id = t2.application_id

请注意,UPDATE中的ORDER BY是不必要的

答案 1 :(得分:0)

您需要通过链接到更新表的WHERE子句来限制子查询,以便它只返回一行。数据库如何知道将哪个值放入哪一行?

UPDATE table1 t1
SET col1 = (SELECT ... FROM table2 t2 WHERE t2.id = t1.some_id)