如何连接多个表,一个表作为动态列,另一个表作为这些列的值

时间:2019-01-14 20:09:11

标签: sql-server pivot

我是SQL Server枢纽的新手,我试图解决一个问题,我需要将以下表输出到一个包含基于一个表的列的值的表中

这是我的桌子

ContactGroup

Title          ID
---------- -----------
Group A         1

ContactsInGroups

ContactId   GroupId
----------- -----------
1           1
2           1
3           1

ContactVariables

ID          Name       GroupId     Order
----------- ---------- ----------- ------
1           Invoice    1           1
2           Due Date   1           1

ContactsVariablesValues

ContactVariableId ContactId   Value
----------------- ----------- -----
1                 1           600

所需的输出

GroupId     ContactId     Invoice     Due Date 
----------- ----------- ----------- -----------
1           1           600           NULL     
1           2           NULL          NULL     
1           3           NULL          NULL     

1 个答案:

答案 0 :(得分:1)

Ali,这是一个至少可以帮助您入门的示例。您可以在SSMS中运行以下命令。

创建一些表变量并插入示例数据。

DECLARE @ContactGroup TABLE ( id INT, title VARCHAR(50) );
INSERT INTO @ContactGroup ( id, title ) VALUES ( 1, 'Group A' );

DECLARE @ContactsInGroup TABLE ( ContactID INT, GroupID INT );
INSERT INTO @ContactsInGroup ( ContactID, GroupID ) VALUES ( 1, 1 ), ( 2, 1 ), ( 3, 1 );

DECLARE @ContactVariables TABLE ( id INT, [name] VARCHAR(50), GroupID INT, [Order] INT );
INSERT INTO @ContactVariables ( id, [name], GroupID, [Order] ) VALUES ( 1, 'Invoice', 1, 1 ), ( 2, 'Due Date', 1, 1 );

DECLARE @ContactsVariablesValues TABLE ( ContactVariableID INT, ContactID INT, [value] INT );
INSERT INTO @ContactsVariablesValues ( ContactVariableID, ContactID, [value] ) VALUES ( 1, 1, 600 );

然后按以下方式查询数据:

SELECT
    ContactGroup.id AS GroupID
    , ContactsInGroup.ContactID
    , ContactVars.Invoice
    , ContactVars.[Due Date]
FROM @ContactGroup AS ContactGroup
INNER JOIN @ContactsInGroup AS ContactsInGroup
    ON ContactGroup.id = ContactsInGroup.GroupID
OUTER APPLY (

    SELECT 
        [Invoice], [Due Date]
    FROM (
        SELECT
            Vars.[name]
            , Vals.[value]
        FROM @ContactVariables AS Vars
        LEFT OUTER JOIN @ContactsVariablesValues Vals
            ON Vars.id = Vals.ContactVariableID
        WHERE
            Vars.GroupID = 1
            AND Vals.ContactID = ContactsInGroup.ContactID

    ) AS ContactData
    PIVOT (
        MIN( [value] )
        FOR [name] IN ( 
            [Invoice], [Due Date] 
        )
    ) AS pvt

) AS ContactVars
ORDER BY
    ContactGroup.id, ContactsInGroup.ContactID;

返回哪个:

+---------+-----------+---------+----------+
| GroupID | ContactID | Invoice | Due Date |
+---------+-----------+---------+----------+
|       1 |         1 | 600     | NULL     |
|       1 |         2 | NULL    | NULL     |
|       1 |         3 | NULL    | NULL     |
+---------+-----------+---------+----------+

注意事项

这里的“魔术”在外部应用中。这使我们可以基于返回的主要数据(在这种情况下为GroupID和ContactID)查询数据的子集。 OUTER APPLY还将返回您希望的具有NULL值的行。

您将在这里遇到一些挑战,即要使用我的示例中所示的PIVOT,您将需要知道将成为列标题的所有值(发票,到期日期等)。根据您的设置,我认为情况可能并非如此,因此您将不得不采用一种在OUTER APPLY中为您创建并执行动态PIVOT语句的技术。

您还可以考虑使用TABLE VALUED FUNCTION来完成PIVOT的工作,然后可以与外部应用程序进行联接。

您有几种选择,但是希望这可以帮助您快速思考。