【问题标题】:BigQuery - Count nulls in columns preserving nested namesBigQuery - 计算保留嵌套名称的列中的空值
【发布时间】:2020-08-18 22:47:13
【问题描述】:

这个问题是这个问题的延伸:BigQuery check entire table for null values

我是 BigQuery 的新手。我有一张大桌子,想避免约 150 个ifnull 电话。但是,一些未嵌套的列名称是相同的,并且没有使用上述问题的答案正确处理它们。这是数据字段的示例

itemId
extension.new.name
extension.new.location
extension.old.name
extension.default
extension.category
...

链接问题的解决方案是:

#standardSQL
SELECT col_name, COUNT(1) nulls_count
FROM `project.dataset.table` t,
UNNEST(REGEXP_EXTRACT_ALL(TO_JSON_STRING(t), r'"(\w+)":null')) col_name
GROUP BY col_name 

我得到的结果有点如下:

col_name    nulls_count
name        5
location    8
default     3
category    7
...

但是由于 group by,此解决方案将 extension.new.nameextension.old.name 视为相同,但我希望每个单独的计数为空:

col_name                nulls_count
extension.new.name      5
extension.new.location  8
extension.old.name      10
extension.default       3
extension.category      7

是否可以使用未嵌套的计数来获取嵌套的列名?我不确定是否有办法捕获整个名称并将它们连接起来?

【问题讨论】:

    标签: google-bigquery


    【解决方案1】:

    以下是 BigQuery 标准 SQL

    #standardSQL
    CREATE TEMP FUNCTION xxx(input STRING)
    RETURNS ARRAY<STRING>
    LANGUAGE js AS '''
      result = [];
      processKey(JSON.parse(input), '');
      function processKey(node, parent) {
        if (parent !== '') {parent += '.'};
        Object.keys(node).map(function(key) {
          if(node[key] == null) {value = null;} else {value = node[key].toString();};
          if (value !== '[object Object]') {
            result.push(parent + key + '|' + value); // ({type:r.type, key:parent + key, value:value});
          } else {
            processKey(node[key], parent + key);
          };
        });         
      };
      return result;
    '''; 
    SELECT COUNT(1) nulls_count, col_name
    FROM (
      SELECT  
        SPLIT(col, '|')[OFFSET(0)] col_name,
        SPLIT(col, '|')[OFFSET(1)] col_value
      FROM `project.dataset.table` t, 
      UNNEST(xxx(TO_JSON_STRING(t))) col
    )
    WHERE col_value = 'null'
    GROUP BY col_name     
    

    您可能想根据自己的特定需求/期望进行调整
    我用几个公共数据集进行了测试,它看起来不太好。

    例如bigquery-public-data.google_analytics_sample.ga_sessions_20170801 表 - 输出为

    Row nulls_count col_name     
    1   2556    visitorId    
    2   1246    totals.timeOnSite    
    3   2513    totals.transactions  
    4   2513    totals.transactionRevenue    
    5   2556    totals.screenviews   
    6   2556    totals.uniqueScreenviews     
    7   2556    totals.timeOnScreen  
    8   2513    totals.totalTransactionRevenue   
    9   1907    trafficSource.referralPath   
    10  2551    trafficSource.keyword    
    11  2544    trafficSource.adContent  
    12  2556    trafficSource.adwordsClickInfo.campaignId    
    13  2556    trafficSource.adwordsClickInfo.adGroupId     
    14  2556    trafficSource.adwordsClickInfo.creativeId    
    15  2556    trafficSource.adwordsClickInfo.criteriaId    
    16  2498    trafficSource.adwordsClickInfo.page  
    17  2498    trafficSource.adwordsClickInfo.slot  
    18  2498    trafficSource.adwordsClickInfo.gclId     
    19  2556    trafficSource.adwordsClickInfo.customerId    
    20  2498    trafficSource.adwordsClickInfo.adNetworkType     
    21  2551    trafficSource.adwordsClickInfo.targetingCriteria     
    22  2498    trafficSource.adwordsClickInfo.isVideoAd     
    23  1684    trafficSource.isTrueDirect   
    24  2556    trafficSource.campaignCode   
    25  2556    device.javaEnabled   
    26  1231    hits.0.isSecure  
    27  1230    hits.0.page.searchKeyword    
    28  1230    hits.0.page.searchCategory   
    29  611     hits.0.transaction.transactionId     
    30  611     hits.0.transaction.transactionRevenue    
    31  611     hits.0.transaction.transactionTax    
    32  611     hits.0.transaction.transactionShipping   
    33  611     hits.0.transaction.affiliation   
    34  611     hits.0.transaction.localTransactionRevenue   
    35  611     hits.0.transaction.localTransactionTax   
    36  611     hits.0.transaction.localTransactionShipping  
    37  611     hits.0.transaction.transactionCoupon     
    38  611     hits.0.item.transactionId    
    39  611     hits.0.item.productName  
    40  611     hits.0.item.productCategory  
    41  611     hits.0.item.productSku   
    42  611     hits.0.item.itemQuantity     
    43  611     hits.0.item.itemRevenue  
    44  611     hits.0.item.localItemRevenue     
    45  1231    hits.0.contentInfo   
    46  1231    hits.0.appInfo.name  
    47  1231    hits.0.appInfo.version   
    48  1231    hits.0.appInfo.id    
    49  1231    hits.0.appInfo.installerId   
    50  1231    hits.0.appInfo.appInstallerId    
    51  1231    hits.0.appInfo.appName   
    52  1231    hits.0.appInfo.appVersion    
    53  1231    hits.0.appInfo.appId     
    54  1231    hits.0.exceptionInfo.description     
    55  1231    hits.0.exceptionInfo.exceptions  
    56  1231    hits.0.exceptionInfo.fatalExceptions     
    57  1231    hits.0.eventInfo     
    58  1015    hits.0.promotionActionInfo   
    59  1231    hits.0.refund    
    60  1231    hits.0.eCommerceAction.option    
    61  1231    hits.0.publisher     
    62  1231    hits.0.social.socialInteractionNetwork   
    63  1231    hits.0.social.socialInteractionAction    
    64  1231    hits.0.social.socialInteractions     
    65  1231    hits.0.social.socialInteractionTarget    
    66  1231    hits.0.social.uniqueSocialInteractions   
    67  1231    hits.0.latencyTracking   
    68  1231    hits.0.sourcePropertyInfo    
    69  1230    hits.0.contentGroup.contentGroupUniqueViews1     
    70  1221    hits.0.contentGroup.contentGroupUniqueViews3     
    71  1231    hits.0.contentGroup.contentGroupUniqueViews4     
    72  1231    hits.0.contentGroup.contentGroupUniqueViews5     
    73  2556    userId   
    74  2556    clientId     
    75  303     hits.0.referer   
    76  684     totals.newVisits     
    77  620     hits.0.contentGroup.contentGroupUniqueViews2     
    78  620     hits.0.transaction   
    79  620     hits.0.item  
    80  22      hits.0.product.0.productRevenue  
    81  22      hits.0.product.0.localProductRevenue     
    82  22      hits.0.product.0.productQuantity     
    83  22      hits.0.product.0.productRefundAmount     
    84  22      hits.0.product.0.localProductRefundAmount    
    85  22      hits.0.product.0.isClick     
    86  22      hits.0.product.0.productCouponCode   
    87  5       trafficSource.adwordsClickInfo.targetingCriteria.boomUserlistId  
    88  216     hits.0.promotionActionInfo.promoIsClick  
    89  1318    totals.bounces   
    

    【讨论】:

      【解决方案2】:

      关于您的问题,我想说明这是由于使用了:

       `UNNEST(REGEXP_EXTRACT_ALL(TO_JSON_STRING(t), r'"(\w+)":nu`ll'))
      

      它只返回最后一个 col_name's 部分(在最后一个 "." 之后),这会导致 col_name 重复,因此只有一个在 group by 之后的 COUNT(1) 中考虑。

      但是,可以更改方法并评估每个 "." 之后的字符串。在您的情况下,您将评估两个表达式:

      • 如果它们有这两个级别,例如:extension.new.name
      • 另外,如果只有一级名称,如:extension.default

      我在下面使用了一个简单的虚拟数据来重现您的案例。

      WITH data AS (
      SELECT 'extension.new.name' as col_name UNION ALL
      SELECT 'extension.new.location' as col_name UNION ALL
      SELECT 'extension.new.location' as col_name UNION ALL
      SELECT 'extension.old.name' as col_name UNION ALL
      SELECT 'extension.default' as col_name UNION ALL
      SELECT 'extension.category ' as col_name 
      )
      SELECT COALESCE(REGEXP_EXTRACT(col_name,r'(\.\w*\.\w*)'),REGEXP_EXTRACT(col_name,r'(\.\w*)')) as col_name1 from data
      group by col_name1
      

      请注意,我特意写了一个名称完全相同的专栏,只是为了检查准确性。另外,我使用了内置方法COALESCE(),它返回第一个非空表达式,加上REGEXP_EXTRACT(),它将:

      1. 搜索具有两个级别的表达式,如:extension.new.name
      2. 搜索具有两个级别的表达式,如:extension.default

      最后按新字段col_name1对数据进行分组,输出如下:

      因此,在您的脚本中,COUNT(1) 将被考虑用于上述所有名称。

      【讨论】:

      • 我认为您对虚拟数据的假设是完全错误的!列名不可用您构造它们的方式!问题的关键在于列名不是那么容易获得 - 所以你的数据 CTE 不存在,而是需要用实际数据构建实际表!!!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-06-07
      • 2020-07-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-28
      • 1970-01-01
      相关资源
      最近更新 更多