如何对此SQL外连接查询进行分组

时间:2011-06-06 16:20:17

标签: sql sql-server sql-server-2008

目前我正在执行以下操作:

SELECT  SiteFeatures.SiteId, Blogs.FeatureInstance_Id as BlogId, 
        PageCollections.FeatureInstance_Id as PagesId, 
        Portfolios.FeatureInstance_Id as PortfolioId
FROM    SiteFeatures 
            LEFT OUTER JOIN Blogs 
                ON SiteFeatures.FeatureInstanceId = Blogs.FeatureInstance_id 
            LEFT OUTER JOIN Portfolios 
                ON SiteFeatures.FeatureInstanceId = Portfolios.FeatureInstance_id 
            LEFT OUTER JOIN PageCollections 
                ON SiteFeatures.FeatureInstanceId = PageCollections.FeatureInstance_id

这将返回如下结果集:

SiteId      BlogId      PagesId     PortfolioId
1           1           NULL        NULL
1           NULL        1           NULL
1           NULL        NULL        1   
2           2           NULL        NULL
2           NULL        2           NULL
2           NULL        NULL        2   

这意味着我必须在我的应用程序代码中聚合这些内容。如何更改我的查询(以性能为准)返回:

SiteId      BlogId      PagesId     PortfolioId
1           1           1           1
1           2           2           2

根据要求 - 我的架构:

dbdiagram

4 个答案:

答案 0 :(得分:3)

SELECT   SiteFeatures.SiteId
         , MAX(Blogs.FeatureInstance_Id) as BlogId
         , MAX(PageCollections.FeatureInstance_Id) as PagesId
         , MAX(Portfolios.FeatureInstance_Id) as PortfolioId
FROM     SiteFeatures 
LEFT OUTER JOIN Blogs 
         ON SiteFeatures.FeatureInstanceId = Blogs.FeatureInstance_id 
LEFT OUTER JOIN Portfolios 
         ON SiteFeatures.FeatureInstanceId = Portfolios.FeatureInstance_id 
LEFT OUTER JOIN PageCollections 
         ON SiteFeatures.FeatureInstanceId = PageCollections.FeatureInstance_id
GROUP BY SiteFeatures.SiteId
ORDER BY SiteFeatures.SiteId ASC

答案 1 :(得分:3)

SELECT
   S.SiteId,
   B.FeatureInstance_Id BlogId, 
   P.FeatureInstance_Id PortfolioId,
   C.FeatureInstance_Id PagesId
FROM
   Sites S
   LEFT JOIN (
      SiteFeatures F1
      INNER JOIN Blogs B ON F1.FeatureInstanceId = B.FeatureInstance_id
   ) ON S.SiteID = F1.SiteID
   LEFT JOIN (
      SiteFeatures F2
      INNER JOIN Portfolios P ON F2.FeatureInstanceId = P.FeatureInstance_id
   ) ON S.SiteID = F2.SiteID
   LEFT JOIN (
      SiteFeatures F3
      LEFT JOIN PageCollections C ON F3.FeatureInstanceId = C.FeatureInstance_id
   ) ON S.SiteID = F3.SiteID

假设您的所有子表每个FeatureInstance_Id只能有一行,这应该可以正常工作。

如果你设计了数据库,那么你就可以在表格中找到不一致的列名,从而获得了很好的说唱力。 :)

如果此查询有效,那么您可以考虑将其封装在一系列视图中,这些视图会将查询返回到一个非常紧凑的东西:

CREATE VIEW BlogsFeature
AS
SELECT
   F.*
FROM
   SiteFeatures F
   WHERE EXISTS ( -- or you could do an INNER JOIN, though in theory this is correct
      SELECT 1
      FROM Blogs B
      WHERE F.FeatureInstanceId = B.FeatureInstance_id
   )

对所有三个表执行此操作将产生以下查询:

SELECT
   S.SiteId,
   B.FeatureInstance_Id BlogId, 
   P.FeatureInstance_Id PortfolioId,
   C.FeatureInstance_Id PagesId
FROM
   Sites S
   LEFT JOIN BlogsFeature B ON S.SiteID = B.SiteID
   LEFT JOIN PortfoliosFeature P ON S.SiteID = P.SiteID
   LEFT JOIN PageCollections C O ON S.SiteID = C.SiteID

实际上,这让我想到了另一种表达你需要的查询的方法,虽然它仍然不是很漂亮:

SELECT
   S.SiteId,
   F1.FeatureInstance_Id BlogId, 
   F2.FeatureInstance_Id PortfolioId,
   F3.FeatureInstance_Id PagesId
FROM
   Sites S
   LEFT JOIN SiteFeatures F1
      ON S.SiteID = F1.SiteID
      AND EXISTS (
         SELECT 1 FROM Blogs B
         WHERE F1.FeatureInstanceId = B.FeatureInstance_id
      ) 
   LEFT JOIN SiteFeatures F2
      ON S.SiteID = F2.SiteID
      AND EXISTS (
         SELECT 1 FROM Portfolios P
         WHERE F2.FeatureInstanceId = P.FeatureInstance_id
      )
   LEFT JOIN SiteFeatures F3
      ON S.SiteID = F3.SiteID
      AND EXISTS (
         SELECT 1 FROM PageCollections C
         WHERE F3.FeatureInstanceId = C.FeatureInstance_id
      )

如果您将uniqueidentifier临时转换为字符串,则可以使用Max()的想法。

SELECT
   S.SiteId,
   B.FeatureInstance_Id BlogId, 
   P.FeatureInstance_Id PortfolioId,
   C.FeatureInstance_Id PagesId
FROM
   SiteFeatures F
   INNER JOIN Blogs B ON 

答案 2 :(得分:1)

您是否尝试使用INNER JOIN而不是LEFT JOIN s?

SELECT  SiteFeatures.SiteId
      , Blogs.FeatureInstance_Id as BlogId 
      , PageCollections.FeatureInstance_Id as PagesId 
      , Portfolios.FeatureInstance_Id as PortfolioId
FROM  SiteFeatures 
          INNER JOIN Blogs 
              ON SiteFeatures.FeatureInstanceId = Blogs.FeatureInstance_id 
          INNER JOIN Portfolios 
              ON SiteFeatures.FeatureInstanceId = Portfolios.FeatureInstance_id 
          INNER JOIN PageCollections 
              ON SiteFeatures.FeatureInstanceId = PageCollections.FeatureInstance_id

第二个想法,这可能是你想要的:

SELECT  sf.SiteId
      , ( SELECT b.FeatureInstance_Id 
          FROM Blogs AS b
          WHERE sf.FeatureInstanceId = b.FeatureInstance_id
        )  AS BlogId 
      , ( SELECT pc.FeatureInstance_Id 
          FROM PageCollections AS pc
          WHERE sf.FeatureInstanceId = pc.FeatureInstance_id
        )  AS PagesId 
      , ( SELECT p.FeatureInstance_Id 
          FROM Portfolios  AS p
          WHERE sf.FeatureInstanceId = p.FeatureInstance_id
        )  AS PortfolioId
FROM  SiteFeatures  AS sf

在第三个想法(并且在看到Eric的答案被接受之后)之后,我将再试一次,只是为了证明它可以用(这种)子查询来完成:

SELECT  s.SiteId
      , ( SELECT b.FeatureInstance_Id 
          FROM Blogs AS b
            JOIN SiteFeatures sf
              ON sf.FeatureInstanceId = b.FeatureInstance_id
          WHERE sf.SiteId = s.SiteId
        )  AS BlogId 
      , ( SELECT pc.FeatureInstance_Id 
          FROM PageCollections AS pc
            JOIN SiteFeatures sf
              ON sf.FeatureInstanceId = pc.FeatureInstance_id
          WHERE sf.SiteId = s.SiteId
        )  AS PagesId 
      , ( SELECT p.FeatureInstance_Id 
          FROM Portfolios  AS p
            JOIN SiteFeatures sf
              ON sf.FeatureInstanceId = p.FeatureInstance_id
          WHERE sf.SiteId = s.SiteId
        )  AS PortfolioId
FROM  Sites  AS s

答案 3 :(得分:1)

由于您使用的是SQL Server 2008,因此以下是使用 CROSS APPLY 的一种可能选项,可能对您有用。它可能不是这里最好看的选择。我只是试了一下。

SELECT          SFR.SiteId
            ,   BLG.FeatureInstance_Id  AS BlogId
            ,   PFL.FeatureInstance_Id  AS PortfolioId
            ,   PGC.FeatureInstance_Id  AS PagesId
FROM            dbo.SiteFeatures    SFR
CROSS APPLY     (
                    SELECT 
                    TOP 1   FeatureInstance_Id
                    FROM    dbo.Blogs BLG
                    WHERE   BLG.FeatureInstance_Id  = SFR.FeatureInstanceId
                ) BLG
CROSS APPLY     (
                    SELECT 
                    TOP 1   FeatureInstance_Id
                    FROM    dbo.PortFolios PFL
                    WHERE   PFL.FeatureInstance_Id  = SFR.FeatureInstanceId
                ) PFL
CROSS APPLY     (
                    SELECT 
                    TOP 1   FeatureInstance_Id
                    FROM    dbo.PageCollections PGC
                    WHERE   PGC.FeatureInstance_Id  = SFR.FeatureInstanceId
                ) PGC