web-dev-qa-db-fra.com

Comment obtenir la somme de toutes les valeurs de colonne de la dernière rangée d'un résultatère sans utiliser l'union?

J'ai besoin d'obtenir la somme de toutes les valeurs de colonne d'un résultat défini dans la dernière ligne. Voici ma requête SQL.

SELECT  CS_YEAR AS YEAR,
        CS_MNTH AS MONTH,
        CS_WK AS WEEK_NO,
        'Total' AS COST_CARRIER,
        'Total' AS COST_CARRIER_CD,
        SUM(CS_WG_CST) AS WAGE_COST,
        SUM(CS_PART_CST) AS MATERIAL_COST,
        SUM(CS_DH_CST) AS DH_SUBLET_COST,
        SUM(CS_TOTAL_CST) AS TOTAL_COST

FROM    ASPECT.WR_CD_CC_RPT_SUMM
WHERE
        CS_CNTRY_CD = '81930' AND
        CS_YEAR = 2016 AND
        CS_MNTH = 1 AND
        CS_WK = 2 AND
        CS_MFC_CD = 'CBU'
GROUP BY CS_YEAR, CS_MNTH, CS_WK

UNION ALL

SELECT  CS_YEAR AS YEAR,
        CS_MNTH AS MONTH,
        CS_WK AS WEEK_NO,
        CS_CC_KIND AS COST_CARRIER,
        CS_CC_CD AS COST_CARRIER_CD,
        CS_WG_CST AS WAGE_COST,
        CS_PART_CST AS MATERIAL_COST,
        CS_DH_CST AS DH_SUBLET_COST,
        CS_TOTAL_CST AS TOTAL_COST

FROM    ASPECT.WR_CD_CC_RPT_SUMM
WHERE
        CS_CNTRY_CD = '81930' AND
        CS_YEAR = 2016 AND
        CS_MNTH = 1 AND
        CS_WK = 2 AND
        CS_MFC_CD = 'CBU'

Je reçois le résultat comme ça-

enter image description here

existe-t-il un moyen alternatif d'obtenir le total de tous les coûts sur la base de l'année, du mois et de la semaine sans utiliser l'union.

2
Govind

Cela dépend vraiment de votre objectif principal - si cela devrait ressembler à 100% comme votre résultat dans la question ci-dessus, je suis désolé que la réponse est non. Si vous voulez obtenir un résultat avec la somme, etc. Oui, il existe des moyens autour du syndicat, mais vous ne voyez peut-être pas le texte "total".

Voici une idée de solution (avec moins de données et de colonnes car je ne pouvais pas l'extraire de votre question).

create table test (year integer, month integer, week integer, cost_carrer char(1),
                    wage_cost decimal(10,2), material_cost decimal (10,2), total_cost decimal(12,2));

insert into test values (2016, 1, 2, '0', 20000.00, 30000.00, 50000.00),
                        (2016, 1, 2, '1', 30000.00, 40000.00, 70000.00),
                        (2016, 1, 2, '2', 25000.00, 35000.00, 60000.00),
                        (2016, 1, 2, '2', 25000.00, 35000.00, 60000.00),
                        (2016, 1, 2, '2', 25000.00, 35000.00, 60000.00);

select year, month, week, cost_carrer, sum(wage_cost), sum(material_cost), sum(total_cost)
 from test
 group by grouping sets ((year, month, week,  cost_carrer), (year, month, week))
 order by year, month, week, cost_carrer

Cela reviendra:

YEAR MONTH WEEK COST_CARRER WAGE_COST MATERIAL_COST TOTAL_COST
 ---- ----- ---- ----------- --------- ------------- ----------
 2016     1    2 0            20000.00      30000.00   50000.00
 2016     1    2 1            30000.00      40000.00   70000.00
 2016     1    2 2            75000.00     105000.00  180000.00
 2016     1    2 NULL        125000.00     175000.00  300000.00

Et je pense que c'est la "idée" derrière votre question et votre exemple.

Autre - Un groupe encore plus puissant de variantes est "Groupe par Rollup" et "Groupe par cube" qui est décrit ici dans la documentation (avec des exemples)

3

As-tu essayé GROUPING SETS? Quelque chose comme:

SELECT  CS_YEAR AS YEAR,
        CS_MNTH AS MONTH,
        CS_WK AS WEEK_NO,
        COALESCE(COST_CARRIER, 'Total') AS COST_CARRIER,
        COALESCE(COST_CARRIER_CD, 'Total') AS COST_CARRIER_CD,
        SUM(CS_WG_CST) AS WAGE_COST,
        SUM(CS_PART_CST) AS MATERIAL_COST,
        SUM(CS_DH_CST) AS DH_SUBLET_COST,
        SUM(CS_TOTAL_CST) AS TOTAL_COST
FROM    ASPECT.WR_CD_CC_RPT_SUMM
WHERE CS_CNTRY_CD = '81930' 
  AND CS_YEAR = 2016 AND
  AND CS_MNTH = 1 AND
  AND CS_WK = 2 AND
  AND CS_MFC_CD = 'CBU'
GROUP BY GROUPING SETS((CS_YEAR, CS_MNTH, CS_WK)
                      ,(CS_YEAR, CS_MNTH, CS_WK, COST_CARRIER_CD, COST_CARRIER));

J'ai utilisé des regroupements pour mapper NULL à 'Total' en supposant que - Say - Cost_Carrier n'est pas NULL. Si vous souhaitez distinguer un "authentique" NULL, et une null groupée, il existe un groupe de fonctions pouvant être utilisé pour le déterminer. Exemple:

select year, month, week
     , case grouping(cost_carrer) 
            when 0 then cost_carrer 
            when 1 then 'Total' 
       end 
...

EDIT: Je vois maintenant que @Michaeltiefeenbacher a répondu de la même manière et que ma seule contribution est l'utilisation de la coalesce. Utilisation de ses échantillons de données:

select year, month, week, coalesce(cost_carrer, 'Total') as cost_carrer
    , sum(wage_cost), sum(material_cost), sum(total_cost) 
from test 
group by grouping sets ((year, month, week,  cost_carrer)
                       ,(year, month, week)) 
order by year, month, week,  cost_carrer;

YEAR        MONTH       WEEK        COST_CARRER 5        6        7                                         
----------- ----------- ----------- ----------- -------- -------- --------
       2016           1           2 0              40000    60000  100000
       2016           1           2 1              60000    80000  140000
       2016           1           2 2             150000   210000  360000
       2016           1           2 Total         250000   350000  600000

Apparemment, j'ai réussi à ajouter les données deux fois, ce qui explique pourquoi mes numéros sont doublés par rapport à Michaels.

Comme indiqué par Michael, vous pouvez également regrouper par Rollup et Cube. Le groupe par le rouleau et le groupe par cube sont "sucre syntaxique" pour les ensembles de regroupement (qui sont à leur tour "sucre syntaxique" pour le groupe des syndicats par). Le groupe par Rollup (A, B, C) est le même que:

group by grouping sets ((a,b,c),(a,b),(a),()). 

Le groupe de Cube est un groupe de regroupement avec le jeu de puissance des attributs de regroupement. Par conséquent, le groupe de cube (A, B, C) est le même que:

group by grouping sets ((a,b,c),(a,b),(a,c),(b,c),(a),(b),(c),()). 

Parmi les utilisations les plus ésotériques du groupe par cube consiste à l'utiliser comme générateur (pas très efficace cependant)

select 1 from ( values 1 ) t(n)
group by cube (n,n,n,n,n)

produira 2 ^ 5 (5 est le nombre de n's dans le cube) = 32 rangées. Pour produire un grand nombre de rangées, il pourrait être tentant d'imbriquer les cubes, mais cela n'est pas autorisé:

SQL0481N  The GROUP BY clause contains "CUBE" nested within "CUBE".
1
Lennart