2010-11-26 8 views
3

J'essaie d'élaborer un rapport de transactions basé sur une plage de dates, pour une entreprise qui peut être ouverte sur deux jours, en fonction de la gestion des équipes.Comment "grouper par" sur une plage DATETIME?

L'utilisateur peut sélectionner une plage de dates (mensuelle, quotidienne, hebdomadaire, libre ...), la requête que j'ai implémentée obtient startDateTime et EndDateTime, et retournera toutes les transactions groupées par jour.

I.E.

DateTime  Total Sales 
--------------------------- 
10/15/2010  $2,300.38 
10/16/2010  $1,780.00 
10/17/2010  $4,200.22 
10/20/2010  $900.66 

Mon problème est que si le changement de l'entreprise est setted, par exemple, 05:00-02h00 du lendemain, toutes les transactions effectuées entre minuit et 02h00 seront regroupées le lendemain ... et ainsi de suite ... les totaux sont corrompus. Lorsqu'une entreprise a un tel changement, elle veut un rapport basé sur ce décalage, mais sans correctif de code (j'utilise Java appelant des requêtes natives Oracle), je ne parviens pas à obtenir le rapport demandé.

Je me demande s'il y a une manière intelligente de grouper par une plage de date/heure ces ensembles de transactions en utilisant rien de plus qu'Oracle.

va ici la requête, pour le mois de Juillet:

SELECT Q1.dateFormat, NVL(Q1.sales, 0) 
    FROM (
     SELECT to_date(to_char(tx.datetimeGMT +1/24 , 'mm-dd-yyyy'), 'mm-dd-yyyy') AS dateFormat      
       , NVL(SUM(tx.amount),0) AS sales 
      FROM Transaction tx 
      WHERE tx.datetimeGMT > to_date('20100801 08:59:59', 'yyyymmdd hh24:mi:ss') +1/24 
       AND tx.datetimeGMT < to_date('20100901 09:00:00', 'yyyymmdd hh24:mi:ss') + 1/24 
      GROUP BY to_date(to_char(tx.datetimeGMT +1/24 , 'mm-dd-yyyy'), 'mm-dd-yyyy') 
    ) Q1 
    ORDER BY 1 DESC 

Répondre

3

Merci à tous pour vos réponses, en prenant un coup d'oeil à eux, je pourrais écrire bas de la requête que je cherchais:

SELECT CASE 
    WHEN EXTRACT(HOUR FROM TX.DATETIME) >= 5 THEN TO_CHAR(TX.DATETIME,'DD-MM-YYYY') 
    WHEN EXTRACT(HOUR FROM TX.DATETIME) BETWEEN 0 AND 2 THEN TO_CHAR(TX.DATETIME-1,'DD-MM-YYYY') 
    WHEN EXTRACT(hour from tx.datetime) between 2 and 5 THEN to_char(TX.DATETIME-1,'DD-MM-YYYY') 
    END AS age, 
    NVL(SUM(tx.amount),0) AS sales 
FROM TRANSACTION TX 
WHERE tx.datetime > to_date('20100801 08:59:59', 'yyyymmdd hh24:mi:ss') 
    AND TX.DATETIME < TO_DATE('20100901 09:00:00', 'yyyymmdd hh24:mi:ss') 
GROUP BY CASE 
    WHEN EXTRACT(HOUR FROM TX.DATETIME) >= 5 THEN TO_CHAR(TX.DATETIME,'DD-MM-YYYY') 
    WHEN EXTRACT(HOUR FROM TX.DATETIME) BETWEEN 0 AND 2 THEN TO_CHAR(TX.DATETIME-1,'DD-MM-YYYY') 
    WHEN EXTRACT(hour from tx.datetime) between 2 and 5 THEN to_char(TX.DATETIME-1,'DD-MM-YYYY') 
    END 
ORDER BY 1 
0

Pour groupe par une plage de dates, vous devez avoir cette gamme en une valeur de colonne dans une sous-requête, et le groupe par celui-ci dans votre requête. Évidemment, cette plage de dates dans cette colonne sera de type VARCHAR.

+0

Ce ne sera pas nécessairement une valeur de varchar. – Donnie

0

Si le premier quart de travail commence à 08h00 et que le dernier jour de ce même jour se termine à 07h59 le jour suivant, vous pouvez utiliser quelque chose comme celui-ci pour regrouper les transactions selon la date du quart.

select trunc(trans_date - interval '8' hour) as shift_date 
     ,sum(amount) 
    from transactions 
group 
    by trunc(trans_date - interval '8' hour) 
order 
    by shift_date desc; 
0

Vous pouvez essayer cette approche (juste hors de ma tête, même pas sûr si elle fonctionne):

select 
trans_date, 
trans_shift, 
aggregates(whatever) 
from (
    select 
    -- we want to group by normalized transaction date, 
    -- not by real transaction date 
    normalized_trans_date, 
    -- get the shift to group by 
    case 
     when trans_date between trunc(normalized_trans_date) + shift_1_start_offset and 
           trunc(normalized_trans_date) + shift_1_end_offset then 
     1 
     when trans_date between trunc(normalized_trans_date) + shift_2_start_offset and 
           trunc(normalized_trans_date) + shift_2_end_offset then 
     2 
     ... 
     when trans_date between trunc(normalized_trans_date) + shift_N_start_offset and 
           trunc(normalized_trans_date) + shift_N_end_offset then 
     N 
    end trans_shift, 
    whatever 
    from (
     select 
     -- get a normalized transaction date: if date is before 1st shift 
     -- it belongs to the day before 
     case 
      when trans_date - trunc(trans_date) < shift_1_start_offset then 
      trans_date - 1 
      else 
      trans_date 
     end normalized_trans_date, 
     t.* 
     from 
     transactions t 
    ) 
) 
group by trans_date, trans_shift