【问题标题】:How to make ClickHouse count() function return 0 in case of zero matches?如果匹配为零,如何使 ClickHouse count() 函数返回 0?
【发布时间】:2017-11-02 15:01:11
【问题描述】:

我们的任务是在 ClickHouse 中运行一批约 20000 个查询,并将结果存储到 CSV 文件中。每个查询都是返回单个数字的 count() 聚合。

我们这样做:

./generate_queries.js | clickhouse-client --multiquery | tr '\n' ',' >> metrics.csv

(是的,尾随逗号,我们会解决这个问题。)

查询示例:

SELECT count(*) FROM merged_data WHERE business_type = 22;

问题在于,如果查询匹配零条记录,ClickHouse 将不返回任何内容,并且生成的 CSV 文件中的记录数与查询数不同。

这可能是 SQL 的标准行为,但我们如何解决这个问题并让 ClickHouse count() 在零匹配的情况下返回 0?

【问题讨论】:

    标签: clickhouse


    【解决方案1】:

    现在你可以这样做:

    SELECT
        count() - 1
    FROM (
        SELECT
            business_type
        FROM
            merged_data
        WHERE
            business_type = 22
        UNION ALL
            toUInt64(1)
    )
    

    只需将toUInt64 替换为business_type 的任何类型即可。

    开发人员已意识到该问题并正在努力解决: https://github.com/yandex/ClickHouse/issues/51 https://groups.google.com/forum/#!topic/clickhouse/2JS_yzvYAHM

    目前的计划是添加一项从设置中控制此行为的功能。

    【讨论】:

      【解决方案2】:

      我们设法使用 JSON 输出格式解决了这个问题。

      SELECT count(*) FROM merged_data WHERE business_type = 22 FORMAT JSONCompact;
      

      这种情况下的数据库响应如下所示:

      {
          "meta":
          [
              {
                  "name": "count()",
                  "type": "UInt64"
              }
          ],
      
          "data":
          [
      
          ],
      
          "rows": 0,
      
          "statistics":
          {
              "elapsed": 0.044646461,
              "rows_read": 53413865,
              "bytes_read": 53413865
          }
      }
      

      总会有响应,即使是空匹配(如果是这种情况,我们会看到 "rows": 0)。

      JSON 响应流解析器​​如下所示:

      var readLine = require('readline');
      
      var rl = readLine.createInterface({
        input: process.stdin,
        output: process.stdout,
        terminal: false
      });
      
      var buf = '';
      
      rl.on('line', line => {
        buf += line;
      
        if (line == '}') {
          // End of JSON => process.
          var json = JSON.parse(buf);
          buf = '';
      
          if (json.rows === 0) {
            console.log('0');
          }
          else {
            console.log(json.data[0][0]);
          }
        }
      });
      

      【讨论】:

        【解决方案3】:

        这是 ClickHouse 的一个已知问题。 要解决此问题,请按照以下步骤操作。

        假设您的计数查询是这样的:

        SELECT count(*) AS count
        FROM mytable
        

        将您的查询放入此 sql 模板中:

        SELECT *
        FROM 
        (
            -- put your count query here 
            UNION ALL 
            SELECT toUInt64(0)
        ) 
        LIMIT 1
        

        所以最终的查询是这样的:

        SELECT *
        FROM 
        (
            SELECT count(*) AS count
            FROM mytable
            UNION ALL 
            SELECT toUInt64 (0)
        ) 
        LIMIT 1
        

        注意:使用此解决方法没有性能开销。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-10-05
          • 2020-01-07
          • 2021-04-25
          • 2021-10-18
          • 1970-01-01
          • 2021-08-25
          相关资源
          最近更新 更多