Postgresql

返回總行數和選定(聚合)數據

  • September 26, 2018

我有一個從表中選擇一些數據的功能。我想返回所選數據和該表中的總行數。

我該如何做到這一點,或者如何以最有效的方式獲得相同的結果?

我嘗試了幾件事,最後得到了下面的程式碼,現在這是我想要的格式,但count(*) over () as total_count會一直返回 1,我需要它返回的是該選擇的總行數records

SELECT 
row_to_json(selected_records) as data
FROM
(   
   SELECT
   count(*) over () as total_count,
   array_to_json(array_agg(row_to_json(records))) as data
   FROM (
       SELECT
           sum(entrances) as entrances
       FROM report_la
       WHERE profile_id = 3777614
       GROUP BY landing_path_id
       limit 10 offset 0
   ) records
) as selected_records

更新了,下面的程式碼正在產生我想要的結果,如果我可以從選擇中隱藏該total_count列會很好records

SELECT 
row_to_json(selected_records) as data
FROM
(   
   SELECT
   min(total_count) as total_count
   ,array_to_json(array_agg(row_to_json(records))) as data
   FROM (
       SELECT
           sum(entrances) as entrances
           ,count(*) over () as total_count
       FROM ga.report_la
       WHERE ga_profile_id = 3777614
       GROUP BY landing_path_id
       limit 10
   ) records
) as selected_records

據我了解,您不需要視窗功能。聚合函式可以完成這項工作:

  • count()在最低級別 (-> row_ct)。
  • sum()結果row_ct進入下一個級別(-> total_row_ct)。
SELECT row_to_json(selected_records)::text AS data
FROM  (   
  SELECT array_to_json(array_agg(row_to_json(records))) AS data
       **, sum(row_ct) AS total_row_ct**
  FROM (
     SELECT **landing_path_id**
          , sum(entrances) AS entrances
          **, count(*) AS row_ct**
     FROM   report_la
     WHERE  profile_id = 3777614
     GROUP  BY landing_path_id
     LIMIT  10
     ) records
  ) selected_records;

我還包括在內landing_path_id,因此結果數據是有意義的。

SQL小提琴。

視窗功能?

視窗函式 ( count(*) over ()) 似乎不是您想要的,因為您沒有未聚合的行。

可以添加到內部子查詢:

count(*) OVER ()

.. 獲得 distinct 的計數landing_path_id,這是另一個可能感興趣的數字。但這似乎不是您所說的“從該記錄中選擇的總行數”。

或者您可以添加到內部子查詢:

sum(count(*)) OVER ()

.. 得到每個冗餘的總數landing_path_id,但這似乎毫無意義。只是為了證明可以在一次傳遞中對聚合函式的結果執行視窗函式。詳細資訊:

更新的問題

您的結果,只是沒有total_countrecords子查詢中。現在佔LIMIT內裡了SELECT。即使landing_path_id選擇了最多 10 個不同的,所有符合條件landing_path_id的都將被計算在內。

為了同時獲得一次掃描和重用計數並分別求和,我引入了一個CTE

WITH cte AS (
 SELECT sum(entrances) AS entrances
      , **count(*) over () AS total_count**
 FROM   report_la
 WHERE  profile_id = 3777614
 GROUP  BY landing_path_id
 LIMIT  10
 )
SELECT row_to_json(selected_records)::text AS data
FROM  (   
  SELECT (SELECT total_count FROM cte LIMIT 1) AS total_count
       , array_to_json(array_agg(row_to_json(records))) AS data
  FROM  (SELECT entrances FROM cte) records
  ) selected_records;

如果您不關心屬性名稱,則可以使用子查詢更便宜:

SELECT row_to_json(selected_records)::text AS data
FROM  (   
  SELECT min(total_count) AS total_count
       , array_to_json(array_agg(row_to_json(**ROW(entrances)**))) AS data
  FROM (
     SELECT sum(entrances) AS entrances
          , count(*) over () AS total_count  -- shouldn't show up in result
     FROM   report_la
     WHERE  profile_id = 3777614
     GROUP  BY landing_path_id
     LIMIT  1
     ) records
  ) selected_records;

您將獲得預設屬性名稱f1而不是entrances,因為ROW表達式不保留列名稱。

如果您需要某個屬性名稱,您可以將該行轉換為已註冊的類型。(Ab-)使用 aTEMP TABLE為會話註冊我的行類型:

CREATE TEMP TABLE rec1 (entrances bigint);

...
       , array_to_json(array_agg(row_to_json(**ROW(entrances)::rec1**))) AS data
...

這將比 CTE 快一點。或者,更詳細但沒有強制轉換

...
       , array_to_json(array_agg(row_to_json(
                  **(SELECT x FROM (SELECT records.entrances) x)**))) AS data
...

此相關答案中的詳細說明:

SQL小提琴。

引用自:https://dba.stackexchange.com/questions/84322