代码之家  ›  专栏  ›  技术社区  ›  Kosmo零

如何将更新行的字段设置为与另一个字段的日期最接近的值?

  •  0
  • Kosmo零  · 技术社区  · 6 年前

    我有一张2米多行的大桌子。 结构是这样的:

    ThingName (STRING),
    Date (DATE),
    Value (INT64)
    

    有时 Value null 我需要通过将其设置为 非空 离它最近的 Date 对应于的行 ThingName ...

    我完全不是SQL的家伙。

    我试图用这个查询来描述我的任务(并通过只使用以前的日期来简化它(但实际上我也需要检查将来的日期)):

    update my_tbl as SDP
    set SDP.Value = (select SDPI.Value
        from my_tbl as SDPI
        where SDPI.Date < SDP.Date
        and SDP.ThingName = SDPI.ThingName
        and SDPI.Value is not null
        order by SDPI.Date desc limit 1)
    where SDP.Value is null;
    

    在那里,我尝试设置更新行 价值 我从同一张表中选择了一个 事物名称 limit 1

    但查询编辑器告诉我: Correlated subqueries that reference other tables are not supported unless they can be de-correlated, such as by transforming them into an efficient JOIN.

    实际上,我根本不确定我的任务是否可以通过查询来解决。

    2 回复  |  直到 6 年前
        1
  •  3
  •   Gordon Linoff    6 年前

    在BigQuery中, update 这是相当罕见的。你似乎想要的逻辑是:

    select t.*,
           coalesce(value,
                    lag(value ignore nulls) over (partition by thingname order by date)
                   ) as value
    from my_tbl;
    

    我真的看不出有什么理由把它放回桌子上。

        2
  •  3
  •   Mikhail Berlyant    6 年前

    下面是BigQuery标准SQL

    在许多(如果不是大多数的话)情况下,您不想更新表(因为它会导致额外的 cost limitations 与…有关 DML statements )而是可以调整查询中的“缺失”值,如以下示例所示:

    #standardSQL
    SELECT 
      ThingName, 
      date, 
      IFNULL(value, 
        LAST_VALUE(value IGNORE NULLS) 
        OVER(PARTITION BY thingname ORDER BY date)
      ) AS value
    FROM `project.dataset.my_tbl`
    

    #standardSQL
    SELECT 
      t1.ThingName, t1.date, 
      ARRAY_AGG(t2.Value IGNORE NULLS ORDER BY t2.date DESC LIMIT 1)[OFFSET(0)] AS value
    FROM `project.dataset.my_tbl` AS t1
    LEFT JOIN `project.dataset.my_tbl` AS t2
    ON t2.ThingName = t1.ThingName
    AND t2.date <= t1.date
    GROUP BY t1.ThingName, t1.date, t1.value
    

    现在您可以使用它来更新您的表,如下例所示

    #standardSQL
    UPDATE `project.dataset.my_tbl` t
    SET value = new_value
    FROM (
      SELECT TO_JSON_STRING(t1) AS id, 
        ARRAY_AGG(t2.Value IGNORE NULLS ORDER BY t2.date DESC LIMIT 1)[OFFSET(0)] new_value
      FROM `project.dataset.my_tbl` AS t1
      LEFT JOIN `project.dataset.my_tbl` AS t2
      ON t2.ThingName = t1.ThingName
      AND t2.date <= t1.date 
      GROUP BY id
    )
    WHERE TO_JSON_STRING(t) = id