【问题标题】:bigquery update table using LIKE returns "UPDATE/MERGE must match at most one source row for each target row"使用 LIKE 的 bigquery 更新表返回“UPDATE/MERGE 必须与每个目标行最多匹配一个源行”
【发布时间】:2021-10-24 16:07:48
【问题描述】:

我有两个表,并想使用 LIKE 语句使用在 table2(映射表)中找到的数据更新 table1(原始数据表)。 但是,我总是收到我所有不同尝试的错误消息:

查询错误:UPDATE/MERGE 必须最多匹配每个源行 目标行

Table1(数据表)

textWithFoundItemInIt         | foundItem
---------------------------------
hallo Adam                    |  
Bert says hello               | 
Want to find "Caesar"bdjehg   |

Table2(映射表)

mappingItem
------------
Adam
Bert
Caesar

预期结果

textWithFoundItemInIt         | foundItem
---------------------------------
hallo Adam                    |  Adam
Bert says hello               |  Bert
Want to find "Caesar"bdjehg   |  Caesar

查询:

UPDATE `table1`
SET foundItem= mt.mappingItem
    FROM `mappingTable` mt
    WHERE textWithFoundItemInIt LIKE CONCAT('%', mt.mappingItem, '%');


UPDATE `table1`
SET foundItem= mt.mappingItem
    FROM `mappingTable` mt
     WHERE INSTR(textWithFoundItemInIt , mt.mappingItem) >1;


UPDATE `table1`
SET foundItem = (SELECT mt.mappingItem FROM `table2` AS mt
WHERE textWithFoundItemInIt LIKE CONCAT('%', mt.mappingItem, '%')
)
WHERE TRUE; 


UPDATE `table1`
SET foundItem= mt.mappingItem
FROM `table1`
inner join  `table2` mt on textWithFoundItemInIt LIKE CONCAT('%', mt.mappingItem, '%');

我还删除了表 1 和表 2 中的所有重复值,但仍然出现相同的错误消息。我也尝试使用 join 语句,但我得到了这个错误消息:“FROM 子句中的别名 table1 已定义为 UPDATE 目标”

我在 SO 中发现了这些类似的问题,并尝试使用他们的方法:

不幸的是,他们对解决我的问题没有帮助。所以我认为这不是一个重复的问题。

非常感谢您的想法。


跟进问题

我指的是@Jon 发布的解决方案。再次感谢您的帮助。但是,在用不同的数据进行测试后,仍然存在如果'table1'中有重复则它不起作用的问题。 当然这个问题来自'GROUP BY'语句 - 如果没有这个,UPDATE查询不起作用,导致我原来的问题中所述的错误消息。如果我对每个值进行 GROUP,它也不起作用。

但是,我的“table1”(数据)和映射表“table2”中可能有重复项。所以说得非常准确,这是我的目标:

Table1(数据表)

textWithFoundItemInIt         | foundItem
-------------------------------------------
hallo Adam                    |  
Bert says hello               | 
Bert says byebye              | 
Want to find "Caesar"bdjehg   |
Want to find "Caesar"bdjehg   |
Want to find "Caesar"again    |
Want to find "CaesarCaesar"again and again | <== This is no problem, just finding one Caesar is enough 

Table2(映射表)

mappingItem
------------
Adam
Bert
Caesar
Bert
Caesar
Adam

预期结果

textWithFoundItemInIt         | foundItem
--------------------------------------------
hallo Adam                    |  Adam
Bert says hello               |  Bert
Bert says byebye              |  Bert
Want to find "Caesar"bdjehg   |  Caesar
Want to find "Caesar"bdjehg   |  Caesar
Want to find "Caesar"again    |  Caesar
Want to find "CaesarCaesar"again and again | Caesar

从 Table2 中找到哪个 Adam 并将其插入 Table1 并不重要,它们都是相同的。因此,如果第一个 Adam 将被第二个 Adam 覆盖,或者一旦找到一个 Adam,查询就停止进一步搜索。

如果我执行 Jon 的 'SELECT' 查询,它会导致:

textWithFoundItemInIt         | foundItem
--------------------------------------------
hallo Adam                    |  Adam
Bert says hello               |  Bert
Bert says byebye              |  Bert
Want to find "Caesar"bdjehg   |  Caesar
Want to find "Caesar"again    |  Caesar
Want to find "CaesarCaesar"again and again | Caesar

它(正确地)省略了第二个“想再次找到“凯撒”,但不幸的是,这不是我需要的。

如果更容易的话,如果在一行中找到两个名字也可以

textWithFoundItemInIt         | foundItem
---------------------------------------------
hallo Adam and Bert           |  Adam, Bert 
Bert says hello to Caesar     |  Bert, Caesar

textWithFoundItemInIt         | foundItem1      | foundItem2
---------------------------------------------------------------
hallo Adam and Bert           |  Adam           | Bert 
Bert says hello to Caesar     |  Bert           | Caesar

我希望这有助于理解我的问题。简而言之:“这只是具有多个相等行的映射”;-)

非常感谢:)

【问题讨论】:

    标签: sql google-bigquery mapping sql-like


    【解决方案1】:

    你的逻辑没有防范这种情况:

    mappingItem
    -----------
    item1
    item12
    

    因为模式%item1% 将匹配item1item12。有很多方法可以避免这种情况,这取决于您希望如何在结构不良的数据中处理这些问题。但这就是原因。

    您可以通过以下方式查找问题:

    SELECT table1.textWithFoundItemInIt
         , COUNT(*)
      FROM table1
      JOIN table2
        ON table1.textWithFoundItemInIt LIKE CONCAT('%', table2.mappingItem, '%')
     GROUP BY table1.textWithFoundItemInIt 
    HAVING COUNT(*) > 1
    

    一旦您决定如何处理这些情况,您应该能够在匹配选项中选择要在UPDATE 中使用的选项。

    基本上,确保逻辑将要分配的值列表(每 table1 行)限制为一 (1) 个值。

    这是一种方法。我不确定 bigquery 是否支持这种特定形式。但它显示了一种合乎逻辑的方法。

    查看数据,注意我们有多个mappingItem 匹配table1 行的情况:

    SELECT table1.textWithFoundItemInIt
         , COUNT(*)
         , MIN(table2.mappingItem) AS theItem1
         , MAX(table2.mappingItem) AS theItem2
      FROM table1
      JOIN table2
        ON table1.textWithFoundItemInIt LIKE CONCAT('%', table2.mappingItem, '%')
     GROUP BY table1.textWithFoundItemInIt 
    HAVING COUNT(*) > 1
    ;
    
    +-----------------------+----------+----------+----------+
    | textWithFoundItemInIt | COUNT(*) | theItem1 | theItem2 |
    +-----------------------+----------+----------+----------+
    | Item12 is a problem   |        2 | item1    | item12   |
    +-----------------------+----------+----------+----------+
    

    现在调整UPDATE 以在分配新值时为每个table1 行选择MIN(mappingItem)

    UPDATE table1
      JOIN ( SELECT textWithFoundItemInIt
                  , MIN(mappingItem) AS mappingItem
               FROM table1
               JOIN table2
                 ON table1.textWithFoundItemInIt LIKE CONCAT('%', table2.mappingItem, '%')
              GROUP BY table1.textWithFoundItemInIt 
           ) mt
        ON table1.textWithFoundItemInIt = mt.textWithFoundItemInIt 
       SET foundItem = mt.mappingItem
    ;
    

    查看结果:

    SELECT * FROM table1;
    
    +----------------------------+-----------+
    | textWithFoundItemInIt      | foundItem |
    +----------------------------+-----------+
    | hallo Item1                | item1     |
    | Item2 says hello           | item2     |
    | Item12 is a problem        | item1     |
    | Want to find "Item3"bdjehg | item3     |
    +----------------------------+-----------+
    

    注意:这会根据原始请求更新所有目标行,甚至包括问题行。这可以调整为仅触及那些尚未设置 foundItem 的行,WHERE foundItem IS NULL

    【讨论】:

    • 感谢您的回复。对不起,我在这个描述中的逻辑确实是不够的。映射项是不同的公司名称,可能不会导致不同的匹配。
    • @Frank 在这种情况下,如果您认为数据不应导致错误,请生成/显示一个最小但完整的测试用例,该测试用例会产生错误,并带有精确的数据。很多时候,我们只是做出被证明是错误的假设。我们都这样做。一个建议是测试你的假设。尝试我显示的诊断查询以查找意外匹配。
    • 我尝试了您的查询,结果出现错误:星形扩展表达式引用列 string_field_0 在 [17:8] 处既未分组也未聚合,因为我的数据表中有更多列。我在这里准备好了我的数据集:filemail.com/d/tkbqrwtanfugbdu
    • @Frank SQL 有意将结果限制为只有多个匹配项。其他的不会造成问题。如果您愿意,可以将此答案标记为helpful,一旦您决定如何处理这些情况,我将能够使用 SQL 更新答案以解决问题。
    • 是的,我认为它很有用,但是我还没有足够的积分来这样做;-)但我已经接受了:) ...只是想知道:为什么会有 HAVING 行COUNT(*) > 1. 还有重复吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-12-22
    • 2011-10-16
    • 2011-08-15
    • 2020-09-20
    • 2021-11-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多