web-dev-qa-db-fra.com

Renvoyer le nombre total de lignes et les données sélectionnées (agrégées)

J'ai une fonction qui sélectionne certaines données d'une table. Je souhaite renvoyer les données sélectionnées et le nombre total de lignes dans ce tableau.

Comment puis-je faire cela ou comment obtenir le même résultat de la manière la plus efficace?

J'ai essayé peu de choses et je me suis retrouvé avec le code ci-dessous, maintenant c'est le format que je veux, mais count(*) over () as total_count retournera 1 tout le temps, ce dont j'ai besoin pour retourner est le nombre total de lignes à partir de ce records sélectionnez.

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

Mis à jour, le code ci-dessous produit le résultat que je veux, ce sera bien si je peux cacher ça total_count dans la colonne records sélectionnez

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
5
RockNinja

Si je comprends bien la question, vous n'avez pas besoin d'une fonction de fenêtre. Les fonctions d'agrégation font le travail:

  • count() au niveau le plus bas (-> row_ct).
  • sum() le row_ct résultant au niveau suivant (-> 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;

J'ai également inclus landing_path_id Afin que les données résultantes aient du sens.

SQL Fiddle.

Fonction fenêtre?

Une fonction de fenêtre (count(*) over ()) ne semble pas être ce que vous voulez, car vous n'avez pas de lignes non agrégées.
Vous pourriez ajouter à la sous-requête interne:

count(*) OVER ()

.. pour obtenir le nombre de landing_path_id distincts, qui est un autre nombre possible qui pourrait être intéressant. Mais cela ne semble pas être ce que vous vouliez dire par "le nombre total de lignes de ces enregistrements sélectionnés".
Ou vous pourriez ajouter à la sous-requête interne:

sum(count(*)) OVER ()

.. pour obtenir le nombre total avec chaque landing_path_id redondant, mais cela semblerait inutile. Il suffit de mentionner que pour démontrer qu'il est possible d'exécuter une fonction de fenêtre sur le résultat d'une fonction d'agrégation en une seule passe. Détails pour cela:

Question mise à jour

Votre résultat, juste sans total_count Dans la sous-requête records. Comptant maintenant le LIMIT dans le SELECT intérieur. Même si un maximum de 10 landing_path_id Distincts est sélectionné, touslanding_path_id Éligibles sont comptés.

Pour obtenir les deux en un seul scan et réutiliser le nombre et la somme séparément, j'introduis un [~ # ~] 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;

Si vous ne vous souciez pas du nom de l'attribut, vous pouvez avoir moins cher avec une sous-requête:

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;

Vous obtenez le nom d'attribut par défaut f1 Au lieu de entrances, car l'expression ROW ne conserve pas le nom de la colonne.

Si vous avez besoin d'un certain nom d'attribut , vous pouvez convertir la ligne en un type enregistré . (Ab-) en utilisant un TEMP TABLE Pour enregistrer mon type de ligne pour la session:

CREATE TEMP TABLE rec1 (entrances bigint);

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

Ce serait un peu plus rapide que le CTE. Ou, plus verbeux mais sans transtypage :

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

Explication détaillée dans cette réponse connexe:

SQL Fiddle.

6
Erwin Brandstetter

Vous pouvez faire ce que a_horse_with_no_name ou ForguesR a suggéré (je pense que la suggestion de a_horse_with_no_name est plus efficace que ForguesR) .. Cependant, ceux-ci vous donneront une colonne supplémentaire dans votre jeu de résultats - que vous souhaitiez ou non. Cela dépend en quelque sorte si vous voulez que cette colonne supplémentaire (affichant toutes les mêmes données répétées) ou si vous voulez une ligne dans votre jeu de résultats qui soit semblable à une "ligne récapitulative".

Ma réponse s'adressera si vous êtes intéressé par un type de résultat "résumé".

Une autre option serait d'avoir une requête qui vous donne la COUNT(*) que vous recherchez, puis UNION avec votre requête d'origine. L'astuce pour cela, bien sûr, est de vous assurer que vous avez le même nombre de colonnes dans les deux requêtes et que la requête COUNT(*) se termine en dernier. Pour ce faire, j'ai ajouté une colonne qui permet de trier par .. Voir l'exemple simple ci-dessous.

-- assume col1, col2 are VARCHAR and col3, col4 are NUMERIC
SELECT
  col1, col2, col3, col4
FROM (
  SELECT
    col1, col2, col3, col4, 1 AS sorter
  FROM tab1
  UNION
  SELECT
    NULL::VARCHAR AS col1, NULL::VARCHAR AS col2, NULL::NUMERIC AS col3, COUNT(*) AS col4, 2 AS sorter
  FROM tab1
) a
ORDER BY a.sorter, a.col1, a.col2;
2
Joishi Bodio

Il vous suffit d'inclure une sous-requête pour obtenir le nombre de toutes les lignes de votre table. Quelque chose comme :

SELECT *, (SELECT COUNT(*) FROM yourTable) AS TotalNbRows FROM yourTable
1
ForguesR

Mettez votre requête agrégée en sous-requête

SELECT COUNT( * ) 
  FROM (
  SELECT COUNT( * ) AS  `count` 
  FROM lms
  WHERE `lead_school_type` =3
  AND subscription.vad =1
  GROUP BY lms.user_id
) AS subcount
0
Ali Azhar