2010-12-12 42 views
0

(Ceci est la version DB2 9.5)Est-ce faisable avec SQL simple? Ou est-ce qu'une procédure est requise?

Dire que j'ai une table avec quatre colonnes:

C1: [EmployeeId] 
C2: [StartDate] yyyy-mm-dd format 
C3: [EndDate] yyyy-mm-dd format 
C4: [Age] 

La combinaison [EmployeeId + StartDate] constitue la clé primaire.
Considérons maintenant les rangées d'exemples suivants:

1  2010-01-16  2010-04-16  29 
2  2010-02-16  2010-03-16  33 
3  2010-05-16  2010-05-16  31 

Il y a une garantie que tous les jours sera le 16e jour, à travers toutes les dates, à travers toutes les lignes. Aucun autre moyen à ce sujet.

Je suis en train d'écrire une requête qui procédez comme suit:

Pour toute ligne où le mois de départ est inférieur au mois de fin (comme la ligne 1), répliquent la ligne pour chaque mois entre , y compris la dernière rangée. Donc, après l'exécution de la requête, les nouvelles lignes de la ligne 1 seront:

1  2010-01-16  2010-04-16  29 
1  2010-02-16  2010-04-16  29 
1  2010-03-16  2010-04-16  29 
1  2010-04-16  2010-04-16  29 

Pour les lignes où le mois de début et le mois de fin sont les mêmes, ne font rien. Pour les lignes où le mois de fin est le mois juste après le mois de départ, une nouvelle ligne sera insérée (voir la dernière ligne ci-dessus pour comprendre pourquoi).

Questions:

  1. Est-ce possible en SQL? Ou est-ce que des procédures sont requises?
  2. Si oui, alors comment? (astuces, code, quoi que ce soit)

Merci d'avoir lu les gars. L'énoncé du problème est complexe, j'espère que j'ai fait un bon travail pour l'expliquer. Toute ambiguïté ou incohérence: veuillez le signaler et je l'éditerai dès que possible.

+0

La plus grande préoccupation que je vois n'a rien à voir avec le SQL, mais avec la garantie que les jours seront le 16e jour. L'expérience me dit que cela va changer dès que le temps aura passé où vous ne comprenez pas pourquoi vous l'avez codé de cette façon pour commencer. –

Répondre

1

Je pense que cela devrait le faire:

 
SELECT e.employee_id, 
     date(extract(year from startdate)||'-'||mm.month_nr||'-'||extract(day from startdate)) as stardate, 
     first_value(e.enddate) over (partition by employee_id order by e.enddate) as enddate 
FROM (
    VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10), (11), (12) 
) mm (month_nr) 
JOIN emp_test e 
    ON mm.month_nr = extract(month from e.startdate) 
ORDER BY e.employee_id, 
     e.startdate, 
     e.enddate

Ceci suppose bien entendu que le type de données pour startdate et enddate est DATE.
Et cela ne fonctionnera que si toutes les dates sont en une seule année.

Je l'ai seulement testé avec DB2 9.7 mais je pense que cela devrait aussi fonctionner avec 9.5.

Je pense qu'il ya une solution pour le problème de l'an-cross:

 
WITH yrs (year_month) AS 
(
    SELECT DATE(year_nr||'-'||month_nr||'-16') 
    FROM (
    VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10), (11), (12) 
) mon (month_nr) 
    CROSS JOIN (
    VALUES (2007), (2008), (2009), (2010), (2011), (2012), (2013) 
) yr (year_nr) 
) 
SELECT e.employee_id, 
     yrs.year_month as startdate, 
     first_value(e.enddate) over (partition by employee_id order by e.enddate) as enddate 
FROM emp_test e 
    JOIN yrs ON yrs.year_month between e.startdate and e.enddate 

Comme vous pouvez le voir les années sont "hardcoded" dans le CTE (expression de table commune). La solution la plus simple consisterait à générer un tableau "mois/année" contenant toutes les valeurs possibles - essentiellement les données générées par le CTE.

+0

N'a pas encore essayé, mais oui, la possibilité (et la probabilité) que les dates peuvent s'étendre sur plusieurs années est un problème majeur. Je vais essayer cela et essayer de construire dessus. Merci pour la perspicacité, très appréciée. –

+0

Le modèle de base pour faire ce travail à travers l'année est d'inclure les années possibles d'une manière ou d'une autre dans la requête. Mon DB2 est un peu rouillé, et je ne sais pas comment le générer dynamiquement (c'est facile pour les valeurs "fixes" comme le numéro du mois) –

0

FWIW un ensemble de contraintes de Attribute- et tuple simplifierait dans une certaine mesure:

CHECK (EXTRACT(DAY FROM StartDate) = 16), 
CHECK (EXTRACT(DAY FROM EndDate) = 16), 
CHECK (StartDate < EndDate)