【问题标题】:MySQL - How do I inner join sorting the joined dataMySQL - 如何内部连接对连接的数据进行排序
【发布时间】:2010-04-05 04:27:52
【问题描述】:

我正在尝试编写一份报告,该报告将加入一个人、他们的工作以及他们在工作时的小时工资。当日期小于工作日期时,我似乎无法找出加入人员费用的最佳方式。

假设一个人在年初的时候每小时花费 30 美元,然后在 2 月 5 日和 3 月 1 日获得了 10 美元的加薪。

  • 01/01/2010 30.00 美元(每小时)
  • 02/05/2010 $40.00
  • 03/01/2010 $45.00

这个人在几天内投入了几个小时。

  • 01/05/2010 10 小时(应为 30 美元/小时)
  • 2010 年 1 月 27 日 5 小时(同样 30 美元)
  • 2010 年 2 月 10 日 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 值?

谢谢!

【问题讨论】:

    标签: sql mysql join


    【解决方案1】:

    最好的解决方案是更改 person_costs 表,以便它记录某个日期间隔(开始和结束)的价格,而不是更改后的价格。只要您不创建任何重叠间隔,联接将始终仅获取每个人/日期的一行。

    如果不能改变表结构,可以创建一个视图,达到同样的效果。

    【讨论】:

    • 这个解决方案最适合我,因为查询比子查询更快(每晚循环数百万条记录)。对于所有边缘情况,为 person_cost 构建 CRUD 更加棘手,但这是值得的。
    【解决方案2】:

    这是我的测试架构:

    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 数据。请注意,我计算的工资率到期日期将是下一个工资率生效的日期,因此我查询的值严格小于到期日期。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-03-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-05-10
      • 2023-03-19
      • 2016-03-08
      相关资源
      最近更新 更多