4

我需要跟踪不同的日期(动态)。因此,对于特定任务,您可以跟踪 X 个日期(例如 DDR1 会议日期、DDR2 会议日期、到期日期等)。

我的策略是创建一个表(DateTypeID、DateDescription)来存储每个日期的描述。然后我可以创建主表(ID、TaskDescription、DateTypeID)。因此,所有日期都将在一列中,您可以通过查看 TypeID 来判断该日期代表什么。问题是在网格中显示它。我知道我应该使用交叉表查询,但我无法让它工作。例如,我在 SQL Server 2000 中使用 Case 语句来旋转表,以便每个列名都是日期类型的名称。如果我们有以下表格:

日期类型表

日期类型ID | 日期描述

 1           | DDR1
 2           | DDR2
 3           | DueDate


任务表

身份证 | 任务描述

1 | Create Design
2 | Submit Paperwork


Tasks_DateType 表

任务ID | 日期类型ID | 日期

1       |     1         | 09/09/2009
1       |     2         | 10/10/2009
2       |     1         | 11/11/2009
2       |     3         | 12/12/2009


结果应该是:

任务描述 | DDR1 | DDR2 | 到期日

Create Design     |09/09/2009 | 10/10/2009 | null
Submit Paperwork  |11/11/2009 | null       | 12/12/2009

如果有人知道我该如何进行研究,我将不胜感激。我这样做而不是为每个日期创建一个列的原因在于能够让用户在未来添加任意数量的日期,而无需手动将列添加到表中并编辑 html 代码。这也允许使用简单的代码来比较日期或按类型显示即将执行的任务(例如“创建设计的 DDR1 日期即将到来”)如果有人能指出我正确的方向,我将不胜感激。

4

4 回答 4

2

这是一个正确的答案,用您的数据进行了测试。我只使用了前两种日期类型,但无论如何你都会动态构建它。

Select 
    Tasks.TaskDescription,     
    Min(Case DateType.DateDescription When 'DDR1' Then Tasks_DateType.Date End) As DDR1,     
    Min(Case DateType.DateDescription When 'DDR2' Then Tasks_DateType.Date End) As DDR2
From
    Tasks_DateType
    INNER JOIN Tasks ON Tasks_DateType.TaskID = Tasks.TaskID
    INNER JOIN DateType ON Tasks_DateType.DateTypeID = DateType.DateTypeID
Group By
    Tasks.TaskDescription

编辑

van 提到没有日期的任务不会出现。这是对的。使用左连接(同样,由 van 提到)并稍微重构查询将返回所有任务,即使目前这不是您的需要。

Select 
    Tasks.TaskDescription,     
    Min(Case DateType.DateDescription When 'DDR1' Then Tasks_DateType.Date End) As DDR1,     
    Min(Case DateType.DateDescription When 'DDR2' Then Tasks_DateType.Date End) As DDR2
From
    Tasks   
    LEFT OUTER JOIN Tasks_DateType ON Tasks_DateType.TaskID = Tasks.TaskID
    LEFT OUTER  JOIN DateType ON Tasks_DateType.DateTypeID = DateType.DateTypeID
Group By
    Tasks.TaskDescription
于 2009-09-16T19:52:35.130 回答
0

我对枢轴运算符没有个人经验,它可能会提供更好的解决方案。

但我过去使用过 case 语句

SELECT 
    TaskDescription, 
    CASE(DateTypeID = 1, Tasks_DateType.Date) AS DDr1, 
    CASE(DateTypeID = 2, Tasks_DateType.Date) AS DDr2,
    ...
FROM Tasks 
    INNER JOIN Tasks_DateType  ON Tasks.ID = Tasks_DateType.TasksID
    INNER JOIN DateType ON Tasks_DateType.DateTypeID = DateType.DateTypeID
GROUP BY TaskDescription

这将起作用,但需要您在添加更多任务描述时更改 SQL,因此并不理想。

编辑:

似乎 PIVOT 关键字是在 SqlServer 2005 中添加的,此示例显示了如何在 2000 和 2005 中进行数据透视查询,但它与我的答案相似。

于 2009-09-16T18:44:27.357 回答
0

如果透视列是未知的(动态的),那么您必须在 ms-sql 2000 或 2005 中手动构建查询,即没有 PIVOT。

这涉及在存储过程中执行动态 sql(通常是禁止的)或使用动态 sql 查询视图。后者是我通常采用的方法。

对于旋转,我更喜欢 Rozenshtein 方法而不是 case 语句,如下所述:

http://www.stephenforte.net/PermaLink.aspx?guid=2b0532fc-4318-4ac0-a405-15d6d813eeb8

编辑

您也可以在 linq-to-sql 中执行此操作,但它会发出一些非常低效的代码(至少当我通过 linqpad 查看它时),所以我不推荐它。如果你仍然好奇,我可以发布一个如何做的例子。

于 2009-09-16T18:50:57.533 回答
0

版本 1: +simple,每次添加 DateType 时都必须更改 -。所以对于动态解决方案来说并不是很好:

SELECT      tt.ID,
            tt.TaskDescription,
            td1.Date AS DDR1,
            td2.Date AS DDR2,
            td3.Date AS DueDate
FROM        Tasks tt
LEFT JOIN   Tasks_DateType td1
        ON  td1.TasksID = tt.ID AND td1.DateTypeID = 1
LEFT JOIN   Tasks_DateType td2
        ON  td2.TasksID = tt.ID AND td2.DateTypeID = 2
LEFT JOIN   Tasks_DateType td3
        ON  td3.TasksID = tt.ID AND td3.DateTypeID = 3

版本 2:完全动态(有一些限制,但可以处理 - 只需 google 即可):

动态透视查询创建。请参阅动态交叉表/数据透视表:您需要创建一个 UDF 的 SP,然后可以将其用于多种用途。这是原始帖子,您可能会发现许多链接和改进。

版本 3只需将其留给您的客户端代码处理。我不会将我的 SQL 设计为返回一组动态数据,而是在客户端(表示层)上处理它。我只是不想处理由于我的查询而出现的一些动态列,我需要猜测那到底是什么。我使用Version-2的唯一原因是当结果直接显示为报表的表格时。在所有其他情况下,真正动态数据我使用客户端代码。例如:拥有你拥有的结构,你将如何附加字段 DueDate 是强制性的逻辑 - 你不能使用数据库约束;您将如何确保 DDR1 不高于 DDR2?如果这些不是数据库中的单独(静态)列(您可以在其中使用 CONSTRAINTS),那么客户端代码就是验证数据一致性的代码。

祝你好运!

于 2009-09-16T19:27:29.950 回答