0
votes

Comment utiliser les mois comme colonnes à partir de la date dans Oracle SQL

J'ai un tableau simple avec des types, des nombres et des dates:

type | April | May | December
-----------------------------
  A  |     1 |   2 |       0
  B  |     0 |   0 |       9

Je dois ajouter les nombres en fonction du type. Mais ce qui me pose problème, c'est que la table résultante doit avoir les mois sous forme de colonnes:

type | number | date
--------------------
  A  |      2 | 15-MAY-2015
  A  |      1 | 15-APR-2015
  B  |      9 | 03-DEC-2015

Comment puis-je utiliser les noms de mois comme colonnes?

J'ai réussi à obtenir les noms des mois en utilisant cette fonction TO_CHAR(table.date, 'Month') AS month .


0 commentaires

3 Réponses :


2
votes

Il s'agit d'une option (exemple de données de la ligne 1 à 5):

SQL> with test (type, num, datum) as
  2    (select 'A', 2, date '2015-05-15' from dual union all
  3     select 'A', 1, date '2015-04-15' from dual union all
  4     select 'B', 9, date '2015-12-03' from dual
  5    )
  6  select type,
  7    max(case when to_char(datum, 'mm') = '04' then num else 0 end) as april,
  8    max(case when to_char(datum, 'mm') = '05' then num else 0 end) as may,
  9    max(case when to_char(datum, 'mm') = '12' then num else 0 end) as december
 10  from test
 11  group by type
 12  order by type;

T      APRIL        MAY   DECEMBER
- ---------- ---------- ----------
A          1          2          0
B          0          0          9

SQL>


2 commentaires

Salut, cela résout presque mon problème. Le problème est que je dois additionner les valeurs, mais votre code ne remplace le nombre que par num. Désolé, car dans mon exemple, vous ne pouviez pas voir les chiffres ajoutés.


Dans ce cas, au lieu de MAX, utilisez la fonction SOMME.



0
votes

Vous pouvez utiliser SYS_REFCURSOR pour une instruction SQL d'agrégation conditionnelle dans une fonction stockée telle que

VAR rc REFCURSOR
EXEC :rc := Get_Totals_For_Months;
PRINT rc

afin d'utiliser les noms de mois comme colonnes ( sans tenir compte de l'année, probablement restée dans une période d'un an seulement )

puis appelez comme

CREATE OR REPLACE FUNCTION Get_Totals_For_Months RETURN SYS_REFCURSOR IS
  v_recordset SYS_REFCURSOR;
  v_sql       VARCHAR2(32767);
  v_cols      VARCHAR2(32767);  
BEGIN

  SELECT LISTAGG('SUM(CASE WHEN TO_CHAR("date",''mm'') = '''||LPAD(level,2,0)||
        ''' THEN "number" END ) AS 
        '||TO_CHAR(TO_DATE(LPAD(level,2,0)||'-01','mm-dd'),'Month'),',') 
           WITHIN GROUP (ORDER BY level)
    INTO v_cols
    FROM dual
 CONNECT BY level <= 12; 

  v_sql := 'SELECT type,'||v_cols||
             ' FROM tab
             GROUP BY type'; 

  OPEN v_recordset FOR v_sql;
  RETURN v_recordset;
END;
/


0 commentaires

2
votes

Utilisez PIVOT :

TYPE | JANUARY | FEBRUARY | MARCH | APRIL |  MAY | JUNE | JULY | AUGUST | SEPTEMBER | OCTOBER | NOVEMBER | DECEMBER
:--- | ------: | -------: | ----: | ----: | ---: | ---: | ---: | -----: | --------: | ------: | -------: | -------:
B    |    null |     null |  null |  null | null | null | null |   null |      null |    null |     null |        9
A    |    null |     null |  null |     1 |    2 | null | null |   null |      null |    null |     null |     null

Lequel, pour les exemples de données:

CREATE TABLE table_name ( type, num, dt ) AS
SELECT 'A', 2, DATE '2015-05-15' FROM DUAL UNION ALL
SELECT 'A', 1, DATE '2015-04-15' FROM DUAL UNION ALL
SELECT 'B', 9, DATE '2015-12-03' FROM DUAL;

Les sorties:

SELECT *
FROM   (
  SELECT type,
         num,
         EXTRACT( MONTH FROM dt ) AS month
  FROM   table_name
)
PIVOT (
  SUM( num ) FOR month IN (
     1 AS January,
     2 AS February,
     3 AS March,
     4 AS April,
     5 AS May,
     6 AS June,
     7 AS July,
     8 AS August,
     9 AS September,
    10 AS October,
    11 AS November,
    12 AS December
  )
)

db <> violon ici


0 commentaires