You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

BigQuery中Insert Into结合Left outer join导致交易行重复翻倍的解决方法

解决BigQuery左外连接插入后数据重复翻倍的问题

你尝试通过自左外连接table2,用上一年数据更新5列字段,再更新Text列,但执行代码后出现行数翻倍、重复行无差异的问题,核心原因是错误使用了INSERT INTO语句,以下是问题分析和修正方案:

原代码问题分析

原INSERT INTO语句会将左连接后的所有结果(包含原表table2的全部行,因为左连接会保留左表所有记录)插入到原表中,相当于把原表数据完整复制了一遍,直接导致行数翻倍。另外,UPDATE语句中的tgt.R_no=b.G_L_no,'0'存在语法错误,字符串连接需要用BigQuery支持的||或CONCAT()函数。

原代码:

insert into table2
select coalesce(a.F_YEAR,b.F_YEAR+1) F_YEAR, 
coalesce(a.POSTING_DATE,b.POSTING_DATE+366)POSTING_DATE,
coalesce(a.Material,b.Material),
coalesce(a.R_no,b.R_no),
coalesce(a.Text,b.Text),
a.Amt,
a.X_BUDGET,
a.Y_BUDGET,
a.X_FORECAST,
a.Y_FORECAST
from table2 a
Left outer join table2 b 
on a.F_YEAR-1 = b.F_YEAR
and extract(month from a.POSTING_DATE) = extract(month from b.POSTING_DATE)
and a.R_no = b.R_no
and a.MATERIAL = b.MATERIAL
and a.TEXT=b.TEXT;

select *
from table2
where F_Year <= extract(year from current_date('Asia/India'));

update table2 tgt
set tgt.TEXT=b.TEXT
from table3 b
where
tgt.R_no=b.G_L_no,'0' and tgt.TEXT is null;

修正方案

根据你的需求(用上一年数据更新现有行,或生成下一年新记录),选择对应的方案:

方案1:更新现有行的5列字段(用上一年数据)

如果你的目标是更新table2中已有行的Amt、X_BUDGET等5列字段为上一年对应数据,使用MERGE语句替代INSERT,避免重复插入:

MERGE INTO table2 tgt
USING (
  SELECT 
    a.F_YEAR,
    a.POSTING_DATE,
    a.Material,
    a.R_no,
    a.Text,
    b.Amt,
    b.X_BUDGET,
    b.Y_BUDGET,
    b.X_FORECAST,
    b.Y_FORECAST
  FROM table2 a
  LEFT JOIN table2 b 
    ON a.F_YEAR - 1 = b.F_YEAR
    AND EXTRACT(MONTH FROM a.POSTING_DATE) = EXTRACT(MONTH FROM b.POSTING_DATE)
    AND a.R_no = b.R_no
    AND a.Material = b.Material
    AND a.Text = b.Text
) src
ON tgt.F_YEAR = src.F_YEAR
  AND tgt.POSTING_DATE = src.POSTING_DATE
  AND tgt.R_no = src.R_no
  AND tgt.Material = src.Material
  AND tgt.Text = src.Text
WHEN MATCHED AND src.Amt IS NOT NULL THEN -- 仅更新存在上一年数据的行
  UPDATE SET
    Amt = src.Amt,
    X_BUDGET = src.X_BUDGET,
    Y_BUDGET = src.Y_BUDGET,
    X_FORECAST = src.X_FORECAST,
    Y_FORECAST = src.Y_FORECAST;

方案2:生成下一年的新记录(不重复原数据)

如果你的目标是基于上一年数据生成下一年的新记录,同样用MERGE确保只插入原表不存在的新记录:

MERGE INTO table2 tgt
USING (
  SELECT 
    b.F_YEAR + 1 AS F_YEAR,
    b.POSTING_DATE + 366 AS POSTING_DATE,
    b.Material,
    b.R_no,
    b.Text,
    b.Amt,
    b.X_BUDGET,
    b.Y_BUDGET,
    b.X_FORECAST,
    b.Y_FORECAST
  FROM table2 b
  -- 过滤掉已存在下一年记录的行,避免重复插入
  WHERE NOT EXISTS (
    SELECT 1 FROM table2 t
    WHERE t.F_YEAR = b.F_YEAR + 1
      AND EXTRACT(MONTH FROM t.POSTING_DATE) = EXTRACT(MONTH FROM b.POSTING_DATE)
      AND t.R_no = b.R_no
      AND t.Material = b.Material
      AND t.Text = b.Text
  )
) src
ON tgt.F_YEAR = src.F_YEAR
  AND EXTRACT(MONTH FROM tgt.POSTING_DATE) = EXTRACT(MONTH FROM src.POSTING_DATE)
  AND tgt.R_no = src.R_no
  AND tgt.Material = src.Material
  AND tgt.Text = src.Text
WHEN NOT MATCHED THEN
  INSERT (F_YEAR, POSTING_DATE, Material, R_no, Text, Amt, X_BUDGET, Y_BUDGET, X_FORECAST, Y_FORECAST)
  VALUES (src.F_YEAR, src.POSTING_DATE, src.Material, src.R_no, src.Text, src.Amt, src.X_BUDGET, src.Y_BUDGET, src.X_FORECAST, src.Y_FORECAST);

修正UPDATE语句

修正字符串连接的语法错误,确保Text列更新逻辑正确:

UPDATE table2 tgt
SET tgt.Text = b.Text
FROM table3 b
WHERE tgt.R_no = b.G_L_no || '0' -- 或使用CONCAT(b.G_L_no, '0')
  AND tgt.Text IS NULL;

验证结果

执行修正后的语句后,再查询数据:

select *
from table2
where F_Year <= extract(year from current_date('Asia/India'));

此时不会出现重复行,数据符合预期。

内容的提问来源于stack exchange,提问作者Abhishek

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 04:12:02