Cross Tab - Storing different dates (Meeting1, Meeting2, Meeting 3 etc) in the same column

后端 未结 4 2083
夕颜
夕颜 2021-01-06 10:49

I need to keep track of different dates (dynamic). So for a specific Task you could have X number of dates to track (for example DDR1 meeting date, DDR2 meeting date, Due Da

相关标签:
4条回答
  • 2021-01-06 11:19

    I don't have personal experience with the pivot operator, it may provide a better solution.

    But I've used a case statement in the past

    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
    

    This will work, but will require you to change the SQL whenever there are more Task descriptions added, so it's not ideal.

    EDIT:

    It appears as though the PIVOT keyword was added in SqlServer 2005, this example shows how to do a pivot query in both 2000 & 2005, but it is similar to my answer.

    0 讨论(0)
  • 2021-01-06 11:25

    If the pivoted columns are unknown (dynamic), then you'll have to build up your query manually in either ms-sql 2000 or 2005, ie with out without PIVOT.

    This involves either executing dynamic sql in a stored procedure (generally a no-no) or querying a view with dynamic sql. The latter is the approach I generally go with.

    For pivoting, I prefer the Rozenshtein method over case statements, as explained here:

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

    EDIT

    You can also do this in linq-to-sql, but it emits some pretty inefficient code (at least when I view it through linqpad), so I don't recommend it. If you're still curious I can post an example of how to do it.

    0 讨论(0)
  • 2021-01-06 11:26

    Here is a proper answer, tested with your data. I only used the first two date types, but you'd build this up on the fly anyway.

    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
    

    EDIT

    van mentioned that tasks with no dates won't show up. This is correct. Using left joins (again, mentioned by van) and restructuring the query a bit will return all tasks, even though this is not your need at the moment.

    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
    
    0 讨论(0)
  • 2021-01-06 11:26

    Version-1: +simple, -must be changed every time DateType is added. So is not great for a dynamic solution:

    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
    

    Version-2: completely dynamic (with some limitations, but they can be handled - just google for it):

    Dynamic pivot query creation. See Dynamic Cross-Tabs/Pivot Tables: you need to create one SP of UDF and then can use it for multiple purposes. This is the original post, to which you may find many links and improvements.

    Version-3: just leave it for your client code to handle. I would not design my SQL to return a dynamic set of data, but rather handle it on the client (presentation layer). I just would not like to handle some dynamic columns that come as a result of my query, where I need to guess what is that exactly. The only reason I use Version-2 is when the result is presented directly as a table for a report. In all other cases for truly dynamic data I use client code. For example: having structure you have, how will you attach logic that field DueDate is mandatory - you cannot use DB constraints; how will you ensure that DDR1 is not higher then DDR2? If these are not separate (static) columns in the database (where you can use CONSTRAINTS), then the client code is the one that validates your data consistency.

    Good luck!

    0 讨论(0)
提交回复
热议问题