2009-01-25 7 views
1

Compte tenu trois tables dates (Date ADate, booléen Douse), Jours (rangeId int, jour int, qté int) et la plage (rangeId int, date startDate) dans Oracleefficace se joindre à une "corrélation" des sous-requêtes

I voulez les joindre de sorte que Range soit joint aux dates de aDate = startDate où doUse = 1 avec chaque jour dans Days.

Si une seule gamme, il peut être fait quelque chose comme ça

SELECT rangeId, aDate, CASE WHEN doUse = 1 THEN qty ELSE 0 END AS qty 
FROM (
    SELECT aDate, doUse, SUM(doUse) OVER (ORDER BY aDate) day 
    FROM Dates 
    WHERE aDate >= :startDAte 
) INNER JOIN (
    SELECT rangeId, day,qty 
    FROM Days 
    WHERE rangeId = :rangeId 
) USING (day) 
ORDER BY day ASC 

Ce que je veux faire est de requête pour toutes les gammes de gamme, pas seulement un.

Le problème est que la valeur de jointure "jour" dépend de la plage startDate à calculer, ce qui me pose des problèmes dans la formulation d'une requête. Gardez à l'esprit que la table Dates est assez volumineuse, donc je voudrais éviter de calculer la valeur du jour à partir de la première date de la table, alors que chaque Range Days ne devrait pas dépasser 100 jours environ.

Modifier: Exemple de données

Dates       Days 
aDate  doUse    rangeId  day  qty 
2008-01-01 1     1   1  1 
2008-01-02 1     1   2  10 
2008-01-03 0     1   3  8 
2008-01-04 1     2   1  2 
2008-01-05 1     2   2  5 

Ranges 
rangeId  startDate 
1   2008-01-02 
2   2008-01-03 


Result 
rangeId  aDate  qty 
1   2008-01-02 1 
1   2008-01-03 0 
1   2008-01-04 10 
1   2008-01-05 8 
2   2008-01-03 0 
2   2008-01-04 2 
2   2008-01-05 5 
+0

Pourriez-vous s'il vous plaît remplir des exemples de données et que souhaitez-vous obtenir en conséquence? – Quassnoi

Répondre

3

Essayez ceci:

SELECT rt.rangeId, aDate, CASE WHEN doUse = 1 THEN qty ELSE 0 END AS qty 
FROM (
    SELECT * 
    FROM (
     SELECT r.*, t.*, SUM(doUse) OVER (PARTITION BY rangeId ORDER BY aDate) AS span 
     FROM (
      SELECT r.rangeId, startDate, MAX(day) AS dm 
      FROM Range r, Days d 
      WHERE d.rangeid = r.rangeid 
      GROUP BY 
       r.rangeId, startDate 
      ) r, Dates t 
     WHERE t.adate >= startDate 
     ORDER BY 
      rangeId, t.adate 
     ) 
    WHERE 
     span <= dm 
    ) rt, Days d 
WHERE d.rangeId = rt.rangeID 
    AND d.day = GREATEST(rt.span, 1) 

PS Il me semble que le seul point à garder tous ces Dates dans la base de données est d'obtenir un calendrier continu avec des vacances marqués.

Vous pouvez générer un calendrier de longueur arbitraire dans Oracle en utilisant la construction suivante:

SELECT :startDate + ROWNUM 
FROM dual 
CONNECT BY 
     1 = 1 
WHERE rownum < :length 

et ne garder que des vacances à Dates. Une simple jointure vous montrera quels sont Dates sont des vacances et qui ne le sont pas.

+1

Pourquoi? Pourquoi générer quelque chose encore et encore et encore. Les tableaux de date sont fabuleusement utiles ... vous pouvez avoir des colonnes pour les vacances, nous avons des CENTAINES de calendriers de vacances, vous pouvez avoir des colonnes pour week-end, jour de semaine, premier jour, dernier jour, ventes promotionnelles, et vous pouvez tout avoir ad hoc q –

+0

La conception initiale avec la table des dates était motivée par le fait de ne pas savoir comment générer des séquences dans Oracle à ce moment-là. Mais maintenant je pense que cela rend l'administration plus facile, le modèle de données que nous utilisons est plus complexe que mon exemple ci-dessus avec des "vacances" différentes pour différents médiums et départements. –

1

Ok, alors peut-être je l'ai trouvé un moyen. Someting comme ceci:

SELECT irangeId, aDate + sum(case when doUse = 1 then 0 else 1) over (partionBy rangeId order by aDate) as aDate, qty 
FROM Days INNER JOIN (
    select irangeId, startDate + day - 1 as aDate, qty 
    from Range inner join Days using (irangeid) 
) USING (aDate) 

Maintenant je dois juste une façon de remplir les dates manquantes ...

Edit: Nah, cette façon signifie que je vais manquer le vaue Arrosez des dernières dates. ..

Questions connexes