2010-04-05 3 views
2

Я пытаюсь написать отчет, который присоединится к человеку, его работе и их почасовой оплате во время работы. Кажется, я не могу найти лучший способ присоединиться к стоимости человека, когда дата меньше даты работы.MySQL - Как мне соединить сортировку объединенных данных?

Скажем, человек стоит $ 30 в час в начале года, то получил рейз $ 10 O 5 февраля, а другой на Мар 1.

  • 01/01/2010 $ 30,00 (в час)
  • 02/05/2010 $ 40,00
  • 03/01/2010 $ 45,00

Люди положить в часах нескольких дней, которые охватывают rasies.

  • 01/05/2010 10 часов (должно быть на уровне $ 30/час)
  • 01/27/2010 5 часов (снова на $ 30)
  • 02/10/2010 10 часов (при $ 40/ч)
  • 03/03/2010 5 часов (при $ 45/час)

Я пытаюсь написать один SQL заявление, которое будет тянуть часы, стоимость за час, и часы * стоимость. Стоимость почасовой ставки последней введенной в систему, поэтому дата стоимость меньше, чем дата работы, упорядочены по дате предела стоимости 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 

проблема у меня, то person_costs не заказан даты в порядке убывания. Он вытаскивает «любое» значение (естественно отсортированное по позиции записи), которое соответствует условию. Как выбрать первое значение person_cost, которое старше даты работы?

Спасибо!

ответ

0

Лучшее решение - изменить таблицу person_costs так, чтобы она записывала цену за интервал дат (начало и конец), а не цену после изменения. Пока вы не создаете перекрывающиеся интервалы, соединение всегда будет извлекать только одну строку на человека/дату.

Если вы не можете изменить структуру таблицы, вы можете создать представление, которое достигнет такого же эффекта.

+0

Это решение будет работать наилучшим образом для меня, поскольку запрос будет быстрее, чем вспомогательный запрос (зацикливая миллионы записей в ночное время). Построение CRUD для person_cost было более сложным со всеми краями, но оно того стоило. – Gary

0

Вот мой тест схема:

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) 

И мой запрос:

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 

В сущности, я вычислил дату конца эффективной ставки заработной платы. В моем примере я исключил присоединение к таблице Person, однако это легко можно включить, чтобы получить данные Person. Обратите внимание, что мой расчет срока действия ставки оплаты будет днем, когда вступит в силу следующая ставка оплаты, и поэтому я запрашиваю значение строго меньше даты истечения срока.

Смежные вопросы