Как сгруппировать этот запрос внешнего соединения SQL - PullRequest
2 голосов
/ 06 июня 2011

В настоящее время я выполняю следующее:

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 ]

3 голосов
/ 07 июня 2011
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
      )

Вы могли бы еще использовать идею Max (), если временно преобразовали свои уникальные идентификаторы в строки.

SELECT
   S.SiteId,
   B.FeatureInstance_Id BlogId, 
   P.FeatureInstance_Id PortfolioId,
   C.FeatureInstance_Id PagesId
FROM
   SiteFeatures F
   INNER JOIN Blogs B ON 
3 голосов
/ 06 июня 2011
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 голос
/ 07 июня 2011

Поскольку вы используете 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
1 голос
/ 07 июня 2011

Вы пытались использовать INNER JOIN с, а не LEFT JOIN с?

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

После третьего размышления (и, увидев принятый ответ Эрика), я сделаю еще одну попытку, просто чтобы показать, что это можно сделать с помощью (такого рода) подзапросов:

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...