简体   繁体   English

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

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

This query returns 40319 records:此查询返回 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 "% %";

Translating above into the following UPDATE query results in all records in alib being updated.将以上转换为以下 UPDATE 查询会导致 alib 中的所有记录都被更新。 Could someone help me understand why this is the case?有人能帮我理解为什么会这样吗?

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 "% %"
       );

I suspect I know why, but turning the update into something like this:我怀疑我知道为什么,但将更新变成这样:

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 "% %";

causes SQLite to complain:导致 SQLite 抱怨:

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

Because there is no WHERE clause on the outer/main UPDATE SQL ie it is basiclly因为外部/主 UPDATE SQL 上没有 WHERE 子句,即它基本上是

UPDATE alib SET composer = the_result_of_the_subquery;
  • ie UPDATE every row.即更新每一行。

You want a WHERE clause to say which rows to update along the lines of :-您需要一个 WHERE 子句来说明要更新的行:-

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

Or to use your code :-或者使用您的代码:-

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
;

This hasn't been fully tested but this may be solution you are looking for :-这尚未经过全面测试,但这可能是您正在寻找的解决方案:-

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);
  • this uses a Common Table Expresssion(CTE) (temporay table that exists just for the query).这使用通用表表达式(CTE)(仅用于查询的临时表)。
  • It utlises the rowid (a hidden column that every table has other than WITHOUT ROWID tables).它使用rowid (每个表都具有的隐藏列,而不是 WITHOUT ROWID 表)。
  • That is the CTE is based upon your original query that extracts the rows from alib that need to be updated.也就是说,CTE 基于您的原始查询,该查询从 alib 中提取需要更新的行。 It only needs the composer from the master table and the rowid of the alib table for the update.它只需要主表中的作曲家和 alib 表的 rowid 即可进行更新。
  • The UPDATE sets the composer to the value of the master_composer column of the respective row from the CTE according to the rowid of the row being updated. UPDATE 根据正在更新的行的 rowid 将 Composer 设置为 CTE 中相应行的 master_composer 列的值。
  • The UPDATEs are only applied to rows that have a matching row in the CTE. UPDATE 仅应用于在 CTE 中具有匹配行的行。

Testing (limited)测试(有限)

The following SQL was used for testing :-以下 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;

Testing Results测试结果

The extracted data :-提取的数据:-

在此处输入图片说明

alib table after UPDATES :-更新后的 alib 表:-

在此处输入图片说明

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

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