繁体   English   中英

为什么这个 SQLite UPDATE 语句会将更改写入表中的所有记录?

[英]Why does this SQLite UPDATE statement write changes to all records in the table?

此查询返回 40319 条记录:

SELECT artist,
       title,
       composer AS alib_composer,
       master.composer AS master_composer
  FROM alib
       INNER JOIN
       master ON hex(alib.__path) = hex(master.__path) AND 
                 alib.l_title = lower(master.title) AND 
                 alib.composer != master.composer AND 
                 length(alib.composer) != length(master.composer) AND 
                 master.composer LIKE "% %" AND 
                 alib.composer NOT LIKE "% %";

将以上转换为以下 UPDATE 查询会导致 alib 中的所有记录都被更新。 有人能帮我理解为什么会这样吗?

UPDATE alib
   SET composer = (
           SELECT composer
             FROM master
            WHERE hex(alib.__path) = hex(master.__path) AND 
                  alib.l_title = lower(master.title) AND 
                  alib.composer != master.composer AND 
                  length(alib.composer) != length(master.composer) AND 
                  master.composer LIKE "% %" AND 
                  alib.composer NOT LIKE "% %"
       );

我怀疑我知道为什么,但将更新变成这样:

UPDATE alib
   SET composer = master.composer
 WHERE hex(alib.__path) = hex(master.__path) AND 
        alib.l_title = lower(master.title) AND 
        alib.composer != master.composer AND 
        length(alib.composer) != length(master.composer) AND 
        master.composer LIKE "% %" AND 
        alib.composer NOT LIKE "% %";

导致 SQLite 抱怨:

Error while executing SQL query on database 'x': no such column: master.composer

因为外部/主 UPDATE SQL 上没有 WHERE 子句,即它基本上是

UPDATE alib SET composer = the_result_of_the_subquery;
  • 即更新每一行。

您需要一个 WHERE 子句来说明要更新的行:-

UPDATE alib SET composer = the_result_of_the_subquery WHERE ??????;

或者使用您的代码:-

UPDATE alib
    SET composer = (
       SELECT composer
         FROM master
        WHERE hex(alib.__path) = hex(master.__path) AND 
              alib.l_title = lower(master.title) AND 
              alib.composer != master.composer AND 
              length(alib.composer) != length(master.composer) AND 
              master.composer LIKE "% %" AND 
              alib.composer NOT LIKE "% %"
   )
WHERE the_expression_to_restrict_which_rows_are_updated
;

这尚未经过全面测试,但这可能是您正在寻找的解决方案:-

WITH cte AS 
    (
        SELECT 
            master.composer AS master_composer,
            alib.rowid AS arowid
        FROM alib
            INNER JOIN
                master ON hex(alib.__path) = hex(master.__path) 
                    AND alib.l_title = lower(master.title) 
                    AND alib.composer != master.composer 
                    AND length(alib.composer) != length(master.composer) 
                    AND master.composer LIKE '% %' 
                    AND alib.composer NOT LIKE '% %'
    )
UPDATE alib 
SET composer = 
    (
        SELECT cte.master_composer FROM cte WHERE cte.arowid = alib.rowid
    ) 
WHERE alib.rowid IN (SELECT arowid FROM cte);
  • 这使用通用表表达式(CTE)(仅用于查询的临时表)。
  • 它使用rowid (每个表都具有的隐藏列,而不是 WITHOUT ROWID 表)。
  • 也就是说,CTE 基于您的原始查询,该查询从 alib 中提取需要更新的行。 它只需要主表中的作曲家和 alib 表的 rowid 即可进行更新。
  • UPDATE 根据正在更新的行的 rowid 将 Composer 设置为 CTE 中相应行的 master_composer 列的值。
  • UPDATE 仅应用于在 CTE 中具有匹配行的行。

测试(有限)

以下 SQL 用于测试:-

DROP TABLE IF EXISTS alib;
DROP TABLE IF EXISTS master;
CREATE TABLE IF NOT EXISTS alib (__path,l_title,composer);
CREATE TABLE IF NOT EXISTS master (__path,title,artist,composer);

INSERT INTO alib VALUES
    ('path1','this','bert'),
    ('path2','something else','Joe'),
    ('path2','something else','Joe'), -- duplicate likely irrelevant but still updated
    ('path2','something else','Joe Someone'), -- already has space in composer skipped
    ('path100','an so on','x') -- no equivalent in master
;
INSERT INTO master VALUES 
    ('path1','this','fred','bert'), -- ignored as no space
    ('path1','this','fred bloggs','Julia smith'),
    ('path2','something else','Alison','Joe Brown')
;

/* DEMO OF EXTRACTED ROWS */
WITH cte AS 
    (
        SELECT 
            master.composer AS master_composer,
            alib.rowid AS arowid 
        FROM alib
            INNER JOIN
                master ON hex(alib.__path) = hex(master.__path) 
                    AND alib.l_title = lower(master.title) 
                    AND alib.composer != master.composer 
                    AND length(alib.composer) != length(master.composer) 
                    AND master.composer LIKE '% %' 
                    AND alib.composer NOT LIKE '% %'
    )
SELECT * FROM cte;

WITH cte AS 
    (
        SELECT 
            master.composer AS master_composer,
            alib.rowid AS arowid 
        FROM alib
            INNER JOIN
                master ON hex(alib.__path) = hex(master.__path) 
                    AND alib.l_title = lower(master.title) 
                    AND alib.composer != master.composer 
                    AND length(alib.composer) != length(master.composer) 
                    AND master.composer LIKE '% %' 
                    AND alib.composer NOT LIKE '% %'
    )
UPDATE alib 
SET composer = 
    (
        SELECT cte.master_composer FROM cte WHERE cte.arowid = alib.rowid
    ) 
WHERE alib.rowid IN (SELECT arowid FROM cte);

SELECT * FROM alib;
DROP TABLE IF EXISTS alib;
DROP TABLE IF EXISTS master;

测试结果

提取的数据:-

在此处输入图片说明

更新后的 alib 表:-

在此处输入图片说明

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM