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

Sql server 如何连接多个表,一个表作为动态列,另一个表作为这些列的值,sql-server,pivot,Sql Server,Pivot,我是SQLServerPivot新手,我正在尝试解决一个问题,即需要将以下表输出到一个表中,其中包含基于一个表的列的值 这是我的桌子 联系人组 联系人组 接触变量 联系人变量值 所需输出 GroupId ContactId Invoice Due Date ----------- ----------- ----------- ----------- 1 1 600 NULL 1

我是SQLServerPivot新手,我正在尝试解决一个问题,即需要将以下表输出到一个表中,其中包含基于一个表的列的值

这是我的桌子

联系人组

联系人组

接触变量

联系人变量值

所需输出

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

阿里,这是一个至少能让你开始的例子。您可以在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     |
+---------+-----------+---------+----------+
返回:

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。OuterApply还将返回具有空值的行,如您所愿

这里您将面临一些挑战,即要使用我的示例中所示的透视,您需要知道将成为列标题的所有值(发票、截止日期等)。根据您的设置,我认为情况可能并非如此,因此您将不得不求助于一种技术,在外部应用程序中为您创建并执行动态PIVOT语句

您也可以考虑使用表值函数来执行可与外部应用程序连接的枢轴工作。


你有几个选择,但希望这有助于启动你的思维

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     |
+---------+-----------+---------+----------+
返回:

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。OuterApply还将返回具有空值的行,如您所愿

这里您将面临一些挑战,即要使用我的示例中所示的透视,您需要知道将成为列标题的所有值(发票、截止日期等)。根据您的设置,我认为情况可能并非如此,因此您将不得不求助于一种技术,在外部应用程序中为您创建并执行动态PIVOT语句

您也可以考虑使用表值函数来执行可与外部应用程序连接的枢轴工作。


你有几个选择,但希望这有助于启动你的思维

截止日期在contactvariable表中,我认为您需要使用动态透视查询,但我认为他们有一个动态模型,并且没有为他们的联系人设置截止日期。我认为dynamic left join pivot可以像excepted一样工作。@RyanWilson Due Date是ContactVariables表中列名的值,order不是id,它是一个列,用于指定列在输出上的顺序。我认为您必须使用游标创建存储过程,动态查询以获取您的例外output@pascalsanchez我不熟悉pivot left join,我会看看能找到什么。我看到一些查询使用pivot,但pivot也使用聚合函数,我的问题是,我需要输出有关可由游标或硬编码生成的列的值。截止日期在contactvariable表中。我认为您需要使用动态透视查询,但我认为它们有一个动态模型,并且没有为其contact设置截止日期。我认为dynamic left join pivot可以像excepted一样工作。@RyanWilson Due Date是ContactVariables表中列名的值,order不是id,它是一个列,用于指定列在输出上的顺序。我认为您必须使用游标创建存储过程,动态查询以获取您的例外output@pascalsanchez我不熟悉pivot left join,我会看看能找到什么。我看到了一些使用pivot的查询,但pivot也使用聚合函数,我的问题是我需要输出有关列的值,这些列可以由游标生成或硬编码。解释得很好,现在我将使用上面的查询说明动态获取列(发票、截止日期),现在,我将使用上述查询动态获取列(发票、截止日期)