2012-01-24 2 views
0

J'ai une base de données MS Access pour la formation des employés et chaque employé doit avoir une classe deux fois par an.Données de ligne d'accès à des colonnes basées sur l'ID

La table pour cette classe ressemble à ceci:

EmployeeID ClassDate ClassHours 
1   1/1/2011  8 
1   7/31/2011  7 
2   2/1/2011  8 
2   8/31/2011  7 
3   3/1/2011  8 
3   9/30/2011  7 

Je veux la table formatté comme ceci:

EmployeeID ClassDate_1 ClassHours_1 ClassDate_2 ClassHours_2 
1   1/1/2011  8   7/31/2011  7 
2   2/1/2011  8   8/31/2011  7 
3   3/1/2011  8   9/30/2011  7 

Comment puis-je écrire une requête pour déplacer la deuxième date de classe et champs heure à la même ligne basée sur le EmployeeID?

J'ai fait des recherches à travers ce site et toutes les solutions possibles semblent être trop compliquées pour ce que j'essaie d'atteindre.

Votre aide est grandement appréciée.

Merci

+0

Je ne ferais pas une table qui ressemble à ça - elle viole la première règle de la normalisation de la base de données. Vous pouvez conserver une table d'employés et une table de classes et écrire une requête qui vous donne les résultats souhaités. – maneesha

+0

Bonjour maneesha. C'est ce que je voudrais faire.Conservez la table d'origine en l'état, mais créez une requête qui déplace les champs communs à l'ID employé vers la même ligne. Je ne sais pas comment écrire la requête pour obtenir ce résultat. – ultraviolet

Répondre

1

Vous devrez créer une requête avec un sous-select

SELECT 
    X.EmployeeID, 
    X.d1 AS ClassDate_1, ec1.ClassHours AS ClassHours_1, 
    X.d2 AS ClassDate_2, ec2.ClassHours AS ClassHours_2 
FROM 
    ((SELECT e.EmployeeID, Min(e.ClassDate) AS d1, Max(e.ClassDate) AS d2 
     FROM employee_classes AS e 
     GROUP BY e.EmployeeID) AS X 
     INNER JOIN employee_classes AS ec1 
      ON X.EmployeeID = ec1.EmployeeID AND X.d1 = ec1.ClassDate 
    ) 
    INNER JOIN employee_classes AS ec2 
     ON X.EmployeeID = ec2.EmployeeID AND X.d2 = ec2.ClassDate; 

Sinon, vous pouvez stocker la sélection imbriquée comme une requête (appelons-le query1):

SELECT e.EmployeeID, Min(e.ClassDate) AS d1, Max(e.ClassDate) AS d2 
FROM employee_classes AS e 
GROUP BY e.EmployeeID 

puis de l'utiliser dans une seconde requête

SELECT 
    X.EmployeeID, 
    X.d1 AS ClassDate_1, ec1.ClassHours AS ClassHours_1, 
    X.d2 AS ClassDate_2, ec2.ClassHours AS ClassHours_2 
FROM 
    (query1 AS X 
     INNER JOIN employee_classes AS ec1 
      ON X.EmployeeID = ec1.EmployeeID AND X.d1 = ec1.ClassDate 
    ) 
    INNER JOIN employee_classes AS ec2 
     ON X.EmployeeID = ec2.EmployeeID AND X.d2 = ec2.ClassDate; 

Il serait beaucoup plus facile si les heures ne sont pas affichés

SELECT e.EmployeeID, Min(e.ClassDate) AS ClassDate_1, Max(e.ClassDate) AS ClassDate_2 
FROM employee_classes AS e 
GROUP BY e.EmployeeID 

En effet, il existe une solution plus simple, mais il suppose que la table est triée par EmployeeID et ClassDate. Cette hypothèse n'est pas sûre, car aucun ordre de tri naturel n'est garanti. Access peut "décider" de réorganiser les enregistrements d'une manière différente à tout moment.

SELECT 
    EmployeeID, 
    First(ClassDate) AS ClassDate_1, First(ClassHours) AS ClassHours_1, 
    Last(ClassDate) AS ClassDate_2, Last(ClassHours) AS ClassHours_2 
FROM 
    employee_classes 
GROUP BY 
    EmployeeID 
ORDER BY 
    EmployeeID; 

Ici encore un sous-select peut aider

SELECT 
    EmployeeID, 
    First(ClassDate) AS ClassDate_1, First(ClassHours) AS ClassHours_1, 
    Last(ClassDate) AS ClassDate_2, Last(ClassHours) AS ClassHours_2 
FROM 
    (SELECT * FROM employee_classes ORDER BY EmployeeID, ClassDate) 
GROUP BY 
    EmployeeID 
ORDER BY 
    EmployeeID; 

Quelle qu'en soit, soit une sous-requête ou une deuxième requête est nécessaire.

+0

Merci beaucoup Olivier. J'ai utilisé votre premier exemple et cela a bien fonctionné. Cependant, parfois, un membre du personnel n'a suivi le cours qu'une seule fois et il n'y a qu'une seule ligne. Comment puis-je implémenter une clause WHERE pour vérifier que ClassDate_2 <> ClassDate_1? – ultraviolet

+0

'IIf (X.d1 = X.d2, nul, X.d2) AS ClassDate_2, IIf (ec1.ClassHours = ec2.ClassHeures, null, ec2.ClassHours) AS ClassHours_2'. Cependant, la solution ne fonctionnera que pour un maximum de deux classes par employé. Si vous avez plus de cours, vous devrez utiliser la solution de ChrisPadgham. –

+0

Olivier, merci beaucoup pour votre aide. Cette solution fonctionne exactement comme j'ai besoin. J'ai juste dû changer la deuxième déclaration de l'IIF pour avoir la même expression que la première déclaration de l'IIF. Les ClassHours sont toujours les mêmes, donc je l'ai changé pour vérifier si les ClassDates sont les mêmes que la condition pour obtenir les heures. Encore une fois, merci pour votre solution. – ultraviolet

0

Cela dépend ce que vous envisagez de faire avec les résultats si elles ne sont que pour l'affichage est ici une requête de tableau croisé qui comprend le ClassDate et les heures dans la cellule de valeur (avec les heures entre parenthèses après la date)

TRANSFORM Last([ClassDate] & " (" & [ClassHours] & ")") AS Details 
SELECT Classes.EmployeeId 
FROM Classes 
GROUP BY Classes.EmployeeId 
PIVOT "Class " & (DCount("[ClassNumber]","[Classes]","[ClassDate]<#" & Format$([ClassDate],"dd-mmm-yyyy") & "# AND [EmployeeId]=" & [EmployeeId])+1); 

cela permettra un nombre quelconque de classes, et pas seulement deux par enseignant.

output from crosstab http://www.solsup.com.au/images/classes.jpg

Questions connexes