如何将多个详细信息表连接到标题表

时间:2011-02-27 15:17:57

标签: sql-server sql-server-2008

我需要将一个Header Table和六个Detail Tables组合成一个结果。为了演示我创建了一个非常简单的示例如下:

DECLARE @MyHeader TABLE (HeaderPK int, Name varchar(100), Total smallmoney)
INSERT INTO @MyHeader (HeaderPK, Name, Total) 
    SELECT 1, 'ABC Company', 1600

DECLARE @MyDetail1 TABLE (Detail1PK int, HeaderFK int, Detail1Description varchar(100), Detail1Amount smallmoney)
INSERT INTO @MyDetail1 (Detail1PK, HeaderFK, Detail1Description, Detail1Amount) 
    SELECT 1, 1, 'Detail 1A', 100
    UNION SELECT 2, 1, 'Detail 1B', 300

DECLARE @MyDetail2 TABLE (Detail2PK int, HeaderFK int, Detail2Description varchar(100), Detail2AmountA smallmoney, Detail2AmountB smallmoney)
INSERT INTO @MyDetail2 (Detail2PK, HeaderFK, Detail2Description, Detail2AmountA, Detail2AmountB) 
    SELECT 1, 1, 'Detail 2A', 100, 100
    UNION SELECT 2, 1, 'Detail 2B', 200, 200
    UNION SELECT 3, 1, 'Detail 3C', 300, 300

-- Returns 2 Rows, Expected 2
SELECT 
    MyHeader.*
    ,MyDetail1.*
FROM
    @MyHeader MyHeader
    FULL JOIN @MyDetail1 MyDetail1 ON MyHeader.HeaderPK = MyDetail1.HeaderFK
ORDER BY
    MyDetail1.Detail1PK

-- Returns 6 Rows, Expected 3
SELECT 
    MyHeader.*
    ,MyDetail1.*
    ,MyDetail2.*
FROM
    @MyHeader MyHeader
    FULL JOIN @MyDetail1 MyDetail1 ON MyHeader.HeaderPK = MyDetail1.HeaderFK
    FULL JOIN @MyDetail2 MyDetail2 ON MyHeader.HeaderPK = MyDetail2.HeaderFK

注意:

  • MSSQL 2008R2
  • 每个明细表将有大约0到15条记录。

在示例中,详细信息表具有类似的结构。在生产系统中,它们非常不同。

3 个答案:

答案 0 :(得分:2)

根据详细信息表的插槽向上检索,这将为您提供所需的内容。坦率地说,我只是因为它有点有趣而展示这段代码。通常没有充分理由进行此类查询。

为了提高传输效率,最好不要重复标题列中的数据:

Header
Detail1
Detail2
Detail3
etc

SQL查询

DECLARE @MyHeader TABLE (HeaderPK int, Name varchar(100), Total smallmoney)
INSERT INTO @MyHeader (HeaderPK, Name, Total) 
    SELECT 1, 'ABC Company', 1600

DECLARE @MyDetail1 TABLE (Detail1PK int, HeaderFK int, Detail1Description varchar(100), Detail1Amount smallmoney)
INSERT INTO @MyDetail1 (Detail1PK, HeaderFK, Detail1Description, Detail1Amount) 
    SELECT 1, 1, 'Detail 1A', 100
    UNION SELECT 2, 1, 'Detail 1B', 300

DECLARE @MyDetail2 TABLE (Detail2PK int, HeaderFK int, Detail2Description varchar(100), Detail2AmountA smallmoney, Detail2AmountB smallmoney)
INSERT INTO @MyDetail2 (Detail2PK, HeaderFK, Detail2Description, Detail2AmountA, Detail2AmountB) 
    SELECT 1, 1, 'Detail 2A', 100, 100
    UNION SELECT 2, 1, 'Detail 2B', 200, 200
    UNION SELECT 3, 1, 'Detail 3C', 300, 300

DECLARE @MyDetail3 TABLE (Detail3PK int, HeaderFK int, Detail3Description sysname)
INSERT INTO @MyDetail3 (Detail3PK, HeaderFK, Detail3Description) 
    SELECT 1, 1, 'Detail 3A'
    UNION SELECT 2, 1, 'Detail 3B'

-- Returns 6 Rows, Expected 3
SELECT 
    MyHeader.*
    ,MyDetail1.*
    ,MyDetail2.*
    ,MyDetail3.*
FROM
    @MyHeader MyHeader
    LEFT JOIN
    (SELECT *, RN=ROW_NUMBER() over (order by Detail1PK) FROM @MyDetail1) MyDetail1
    FULL JOIN
    (SELECT *, RN=ROW_NUMBER() over (order by Detail2PK) FROM @MyDetail2) MyDetail2
    ON MyDetail1.HeaderFK = MyDetail2.HeaderFK AND MyDetail1.RN = MyDetail2.RN
    FULL JOIN
    (SELECT *, RN=ROW_NUMBER() over (order by Detail3PK) FROM @MyDetail3) MyDetail3
    ON COALESCE(MyDetail1.HeaderFK, MyDetail2.HeaderFK) = MyDetail3.HeaderFK
       AND COALESCE(MyDetail1.RN, MyDetail2.RN) = MyDetail3.RN
    ON MyHeader.HeaderPK = COALESCE(MyDetail1.HeaderFK, MyDetail2.HeaderFK)

您可以通过向COALSECE添加更多详细信息来扩展到更多详细信息表,因此第6个详细信息表将是

    FULL JOIN
    (SELECT *, RN=ROW_NUMBER() over (order by Detail6PK) FROM @MyDetail6) MyDetail6
    ON COALESCE(MyDetail1.HeaderFK, MyDetail2.HeaderFK, MyDetail3.HeaderFK,
        MyDetail4.HeaderFK, MyDetail5.HeaderFK) = MyDetail6.HeaderFK
       AND COALESCE(MyDetail1.RN, MyDetail2.RN, MyDetail3.RN, MyDetail4.RN, MyDetail5.RN) = MyDetail6.RN

答案 1 :(得分:0)

对每一行执行每个连接。因此,如果您在一个匹配2行的表上连接一行表,那么您将获得2行。如果你在一个包含3行的表上加入它,你会获得6行,依此类推。

一种解决方案是执行多个SQL语句,每个详细信息表一个。客户端可以使用等效的SqlDataReader.NextResult()移动到下一个结果。

另一种选择是将union all不同的陈述放在一起;这将导致列太多,但行数将减少。

答案 2 :(得分:0)

当你将@ MyDetail1与@MyHeader匹配时,你会得到两行。如果你将@ MyDetail2与@MyHeader匹配,你会获得三行。但是,在上一次连接中,您不告诉系统如何将@ MyDetail1中的两行与@ MyDetail2中的三行匹配,因此系统假定您要将@ MyDetail1的每一行与@ MyDetail2的每一行匹配得到2 x 3行或6行。

解决方案:

  1. 如果@ MyDetail1和@ MyDetail2应该彼此直接相关,那么就会缺少一个Join。
  2. 如果你只想要@ MyDetail1然后是@ MyDetail2,那么请使用两个Select子句。