簡體   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