【问题标题】:SQL Linked tables by earlier date for each record每条记录按较早日期的 SQL 链接表
【发布时间】:2015-05-15 12:09:56
【问题描述】:

描述我的问题并不容易。 Task 在不同的时间范围内有不同的子任务。根据每条任务记录(Task表)的日期从子任务表中获取较早的子任务列表。

  • Task 表有列 T1Date, T1Task
  • Subtask 表有列T2TaskT2SubTaskT2Date

  • Table2.T2Task 链接到Table1.T1Task

Table2 列出每个任务的所有子任务以及每个子任务的生效日期。

例如:

Table1 记录:

01/17/2015, Task1
02/24/2015, Task1
03/01/2015, Task2
05/01/2015, Task2

在不同的日期总共执行了四个任务。

Table2 记录:

Task1, SubTask1_1, 01/15/2015
Task1, SubTask1_2, 01/15/2015
Task1, SubTask1_3, 01/15/2015
Task1, SubTask1_1, 02/15/2015
Task1, SubTask1_4, 02/15/2015
Task2, SubTask2_1, 01/01/2015
Task2, SubTask2_2, 04/01/2015
Task2, SubTask2_3, 07/01/2015

这意味着Task1 携带子任务 1_1、1_2 和 1_3,如果它发生在 2015 年 1 月 15 日到 2015 年 2 月 14 日之间。并且 Task1 从 2015 年 2 月 15 日及之后更改为子任务 1_1 和 1_4

我需要 SQL 结果:

01/17/2015, Task1, SubTask1_1, 01/15/2015
01/17/2015, Task1, SubTask1_2, 01/15/2015
01/17/2015, Task1, SubTask1_3, 01/15/2015
02/24/2015, Task1, SubTask1_1, 02/15/2015
02/24/2015, Task1, SubTask1_4, 02/15/2015
03/01/2015, Task2, SubTask2_1, 01/01/2015
05/01/2015, Task2, SubTask2_2, 04/01/2015

我可以使用下面的 SQL 来获取带有硬编码日期的最新结果。但是,我不知道如何使用到达记录的 T1Date 来替换下面 SQL 上的#2/1/2015#。

SELECT 
    T1Date, T1Task, T2SubTask, T2Date 
FROM 
    Table1 
INNER JOIN 
    (SELECT 
         Table2.T2Task, Table2.T2subTask, MAX(Table2.T2Date) as maxdate 
     FROM 
         Table2 
     WHERE 
         Table2.T2Date <= #2/1/2015# 
     GROUP by 
         T2subtask) AS b ON Table1.T1Task = b.T2Task AND Table2.Date = b.maxdate

【问题讨论】:

  • 这是n-n 关系!!!这是您在关系数据库中可以做的最糟糕的事情。
  • 这适用于哪个 RDBMS?请添加标签以指定您使用的是mysqlpostgresqlsql-serveroracle 还是db2 - 或其他完全不同的东西。

标签: sql


【解决方案1】:

如果您没有 SQL Server 2012 或更高版本,则可以在 select 中使用相关子查询来确定每个任务的先前日期

;WITH T1Tasks AS (
    SELECT t.*
    ,      ISNULL((SELECT MAX(p.T1Date) FROM Table1 AS p WHERE p.T1Task = t.T1Task AND p.T1Date < t.T1Date),'January 1, 1753') AS PriorDate
    FROM   Table1 AS t
)
SELECT  T1Task
,       T1Date
,       PriorDate
,       ISNULL( T2Task, 'null' ) AS T2Task
,       ISNULL( T2SubTask, 'null' ) AS T2SubTask
,       ISNULL( T2Date, DATEADD(YEAR,100,GETDATE()) ) AS T2Date
FROM    T1Tasks AS T1
LEFT JOIN   Table2 AS T2
    ON  T2.T2Task = T1.T1Task
    AND T2.T2Date BETWEEN PriorDate AND T1Date

SQLFiddle 链接:http://sqlfiddle.com/#!6/5a2b6/66/0

【讨论】:

    【解决方案2】:

    如果您使用的是 SQLServer 2012 或更高版本,则可以使用 OVER 窗口函数的 ROWS 参数从 Table1 中获取上一个日期,从而创建 T2 日期应属于的日期范围:

    ;WITH Table1WithPriorDate AS (
        SELECT  T1Task
        ,       T1Date
        ,       MIN(T1Date) OVER (
                    PARTITION BY T1Task
                    ORDER BY T1Date
                    ROWS BETWEEN 1 PRECEDING AND CURRENT ROW
                ) AS PriorDate
        FROM    Table1
    ), T1Tasks AS (
        SELECT  T1Task
        ,       T1Date
        ,       CASE PriorDate
                WHEN T1Date THEN 'January 1, 1753'
                ELSE PriorDate
                END AS PriorDate
        FROM    Table1WithPriorDate
    )
    SELECT  T1Task
    ,       T1Date
    ,       PriorDate
    ,       ISNULL( T2Task, 'null' ) AS T2Task
    ,       ISNULL( T2SubTask, 'null' ) AS T2SubTask
    ,       ISNULL( T2Date, DATEADD(YEAR,100,GETDATE()) ) AS T2Date
    FROM    T1Tasks AS T1
    LEFT JOIN   Table2 AS T2
        ON  T2.T2Task = T1.T1Task
        AND T2.T2Date BETWEEN PriorDate AND T1Date
    

    SQLFiddle 链接:http://sqlfiddle.com/#!6/5a2b6/59

    【讨论】:

      猜你喜欢
      • 2020-08-22
      • 1970-01-01
      • 2021-01-05
      • 2023-01-30
      • 1970-01-01
      • 2018-01-04
      • 2020-12-16
      • 2020-12-12
      • 2015-12-10
      相关资源
      最近更新 更多