【问题标题】:Display default value if query results in no records in BigQuery如果查询结果在 BigQuery 中没有记录,则显示默认值
【发布时间】:2018-06-05 20:36:01
【问题描述】:

查询可以在 BigQuery 上返回一个空表。发生这种情况的一个例子是,如果我在 BigQuery 上的查询中 join 一堆表并且连接的结果是一个空表,或者如果没有基于 where 子句的匹配项。

这是一个愚蠢的示例查询,它总是以空连接返回:

#standardSQL
WITH query1 AS (
    SELECT 1 AS number, "one" AS message
), query2 AS (
    SELECT 2 AS number, "two" AS message)
SELECT "query result" AS result, query1.* 
FROM query1
JOIN query2 ON query1.number = query2.number;

查询将显示以下输出:Query returned zero records.

如果是这种情况,我想返回一条消息或默认行。但我不知道该怎么做。我试过使用IFNULL,但这仅适用于一列,而不是列数。使用 IF 语句给了我错误,因为您无法从 if 语句返回行。 我认为它给我的错误是Scalar subquery cannot have more than one column unless using SELECT AS STRUCT to build STRUCT values

我能想到但不知道如何实现的另一件事是在末尾添加一个UNION,只有在前面的部分没有返回任何内容时才会触发。或者将现有查询包装在 WITH 语句子查询中,如果没有返回任何内容,则打印一条消息,否则执行 SELECT * FROM sub_query

我想在结果为空表时仅显示一条消息,或者返回带有一些默认值的行。 我知道答案可能包含UNION 语句,因此不可能只显示一条消息。在这种情况下,我想改为显示默认行。对于上述示例查询,默认行如下所示:"No results found", NULL, NULL。 当查询返回一个非空表时,我希望它看起来与原始查询完全一样。所以不应该有任何添加列或更改结果的架构。

【问题讨论】:

    标签: sql google-bigquery


    【解决方案1】:

    选项一

    如果没有为 your_query 返回结果,下面显示全为空的行

    #standardSQL
    WITH your_query AS ( ... )
    SELECT * FROM your_query 
    UNION ALL 
    SELECT your_query.* REPLACE ("No results found" AS result)
    FROM (SELECT 1) 
    LEFT JOIN your_query ON FALSE
    WHERE NOT EXISTS (SELECT 1 FROM your_query)  
    
    Row result              number  message  
    1   No results found    null    null     
    

    选项 2

    如果您事先知道输出模式 - 下面返回默认行(假设 number 的默认值为 0,message 的默认值为“无”

    #standardSQL
    WITH your_query AS ( ... )
    SELECT * FROM your_query 
    UNION ALL 
    SELECT "No results found", 0, "none" FROM (SELECT 1) 
    LEFT JOIN your_query ON FALSE
    WHERE NOT EXISTS (SELECT 1 FROM your_query)
    
    Row result              number  message  
    1   No results found    0       none     
    

    【讨论】:

    • 我也赞成您的回答,因为它完全符合我的要求。请注意,您应该更新第二个查询,以便 select 语句读取类似于 "result", 0, "none"(您缺少一个字符串作为选择的第一个值)
    • 你是对的。我只是不确定你是否需要那个“结果”字段。不知何故,我认为这是额外的 - 但如果出于某种原因你需要它 - 好的 :o)
    • 没有它,查询将无法运行,因为列号不匹配
    • 明白了——我在你原来的查询中引用了"query result" AS result——你为什么需要它?
    • 哦,我明白了。这并不是真正需要的。我只是想在select 中添加一些东西,这样它就不仅仅是query1.*
    【解决方案2】:

    您将使用union all。像这样的:

    with t as (
          . . . <all your query stuff here>
         )
    select cast(NULL as string) as msg, t.*
    from t
    union all
    select msg, t.*  -- all the `t` columns will be `NULL`
    from (select 'No rows returned' as msg) left join
         t
         on 1 = 0  -- always false
    where not exists (select 1 from t);
    

    注意并发症。查询返回一组具有固定名称的固定列。此版本在数据的开头返回一个额外的列来包含消息。为了获取所有其余列,使用了left join,但on 子句始终为假。

    【讨论】:

    • 我赞成您的帖子,因为它回答了我的问题。你能想出一种不引入新列的方法吗?
    • @alamoot 。 . .您可以将字符串放入任何现有的字符串列,但您的问题并没有真正解释结果集应该是什么样子。
    • 好点,我在问题的末尾添加了一段描述结果的预期行为
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多