2010-04-05 9 views
2

J'essaie d'écrire un rapport qui rejoindra une personne, leur travail, et leur salaire horaire au moment du travail. Je n'arrive pas à trouver le meilleur moyen de joindre le coût de la personne lorsque la date est inférieure à la date du travail.MySQL - Comment puis-je jointure interne tri des données jointes

Disons que une personne coûte 30 $ par heure au début de l'année, puis a obtenu une augmentation de 10 $ o 5 février et un autre le 1er mars

  • 01/01/2010 30,00 $ (par heure)
  • 02/05/2010 40,00 $
  • 03/01/2010 45,00 $

La personne mis en heures plusieurs jours qui enjambent les rasies.

  • 01/05/2010 10 heures (devrait être à 30 $/h)
  • 01/27/2010 5 heures (de nouveau à 30 $)
  • 02/10/2010 10 heures (à 40 $/h)
  • 03/03/2010 5 heures (à 45 $/h)

Je suis en train d'écrire une instruction SQL qui va tirer les heures, le coût par heure, et les heures * coût. Le coût est le taux horaire dernier entré dans le système si la date de coût est inférieur à la date de travail, ordonnée par date limite de coût 1.

SELECT person.id, person.name, work.hours, person_costs.value, 
     work.hours * person_costs.value AS value 
    FROM person 
    JOIN work ON person.id = work.person_id 
    JOIN person_costs ON person.id = person_costs.person_id 
        AND person_costs.date < work.date 
WHERE person.id = 1234 
ORDER BY work.date ASC 

Le problème que je vais avoir, les person_costs ne sont pas commandés par date dans l'ordre décroissant. Il sort "any" valeur (naturellement triée par position d'enregistrement) qui correspond à la condition. Comment puis-je sélectionner la première valeur person_cost qui est plus ancienne que la date de travail?

Merci!

Répondre

0

La meilleure solution consiste à modifier la table person_costs afin qu'elle enregistre le prix sur un intervalle de dates (début et fin) plutôt que sur le prix après un changement. Tant que vous ne créez aucun intervalle de chevauchement, la jointure ne récupère qu'une seule ligne par personne/date.

Si vous ne pouvez pas modifier la structure de la table, vous pouvez créer une vue qui réalise le même effet.

+0

Cette solution fonctionnera le mieux pour moi car la requête sera plus rapide qu'une sous-requête (en boucle sur des millions d'enregistrements tous les soirs). Construire le CRUD pour le person_cost était plus compliqué avec toutes les valises, mais ça en valait la peine. – Gary

0

Voici mon schéma de test:

Create Table person_cost 
        (
        PersonId int not null 
        , Rate decimal(15,4) not null 
        , [date] datetime not null 
        , Constraint PK_person_cost Primary Key Clustered (PersonId, [date]) 
        ) 
Insert person_cost(PersonId, Rate, [date]) Values(1,30,'2010-01-01') 
Insert person_cost(PersonId, Rate, [date]) Values(1,40,'2010-02-05') 
Insert person_cost(PersonId, Rate, [date]) Values(1,50,'2010-03-01') 

Create Table Work 
       (
       PersonId int not null 
       , [Date] datetime not null 
       , Hours int not null 
       ) 

Insert Work(PersonId, [Date], Hours) Values(1, '2010-01-05', 10) 
Insert Work(PersonId, [Date], Hours) Values(1, '2010-01-27', 5) 
Insert Work(PersonId, [Date], Hours) Values(1, '2010-02-10', 10) 
Insert Work(PersonId, [Date], Hours) Values(1, '2010-03-03', 5) 

Et ma requête:

Select Work.PersonId, Work.Hours, PayRanges.Rate 
    , Work.Hours * PayRanges.Rate As Value 
From Work 
    Join (
      Select pc1.PersonId, pc1.[date] As StartDate, Rate 
       , Coalesce((Select Min(pc2.[date]) 
        From person_cost As pc2 
        Where pc2.personId = pc1.personId 
         And pc2.[date] > pc1.[date]) 
        , '9999-12-31') As NextEffectiveDate 
      From person_cost As pc1 
      ) As PayRanges 
     On Work.PersonId = PayRanges.PersonId 
      And Work.[Date] >= PayRanges.StartDate 
      And Work.[Date] < PayRanges.NextEffectiveDate 

Essentiellement, je calcule la date de fin du taux de rémunération efficace. Dans mon exemple, j'ai exclu une jointure à la table Person, cependant cela peut facilement être inclus pour obtenir des données Person. Notez que mon calcul de la date d'expiration d'un taux de rémunération sera le jour où le prochain taux de rémunération prend effet et donc je demande une valeur strictement inférieure à la date d'expiration.