2013-05-31 152 views
2

我有如下表 -MS SQL - 一對多的關係 - 需要返回單列

Search Result 
---------------- 
SearchResultID PK 
ProductID FK 
SearchQuery 
WebsiteName 
URL 
IsFound 
CreatedOn 
BatchID 
Name 

SearchResultItem 
----------------- 
SearchResultItemID PK 
SearchResultID FK 
Name 
Value 

這些表有一對多的關係,因此一個搜索結果,可以有多個搜索結果項。

我可以在這些表上做一個INNER JOIN,但是每個搜索結果項目顯然會給出一行。理想情況下,我希望每個搜索結果有一行,例如...

SearchResultID | ProductID | SearchQuery | WebsiteName | URL | IsFound | 
CreatedOn | BatchID | Name | SearchResultItemID | Name 1 | Value 1 | Name 2 | 
Value 2 | Name 3 | Value 3 | 

這可能嗎?如果是這樣,有人可以指出我正確的方向,我將如何做到這一點 - 我認爲這將是這樣的,只有在MS - SQL - one to many sql select into single row - mysql

+0

有很多方法可以做到這一點。你知道你有多少結果嗎?你想把每行的信息連接在一起成一列還是你想爲每一行分開一列? –

+0

Hi @DavidSöderlund,理想情況下,我想爲每一行分開一列,我也可以事先知道我需要的結果數量,例如,我知道這個查詢將有3組名/值.. – 109221793

回答

4

您可以使用ROW_NUMBER()函數給每個搜索結果項目每個搜索結果中的排名:

SELECT SearchResultItemID, 
     SearchResultID, 
     Name, 
     Value, 
     RowNumber = ROW_NUMBER() OVER(PARTITION BY SearchResultID ORDER BY SearchresultItemID) 
FROM SearchResultItem; 

如果你有一個項目瞭解數字,那麼你可以使用集合函數來獲取每個名稱/值對:

WITH RankedItem AS 
( SELECT SearchResultItemID, 
      SearchResultID, 
      Name, 
      Value, 
      RowNumber = ROW_NUMBER() OVER(PARTITION BY SearchResultID ORDER BY SearchresultItemID) 
    FROM SearchResultItem 
) 
SELECT SearchResultID, 
     Name1 = MIN(CASE WHEN RowNumber = 1 THEN Name END), 
     Value1 = MIN(CASE WHEN RowNumber = 1 then Value END), 
     Name2 = MIN(CASE WHEN RowNumber = 2 THEN Name END), 
     Value2 = MIN(CASE WHEN RowNumber = 2 then Value END), 
     Name3 = MIN(CASE WHEN RowNumber = 3 THEN Name END), 
     Value3 = MIN(CASE WHEN RowNumber = 3 then Value END), 
     Name4 = MIN(CASE WHEN RowNumber = 4 THEN Name END), 
     Value5 = MIN(CASE WHEN RowNumber = 4 then Value END) 
FROM RankedItem 
GROUP BY SearchResultID; 

然後,您可以加入這個回到您的搜索結果表g艾爾文一個完整的查詢:

WITH RankedItem AS 
( SELECT SearchResultItemID, 
      SearchResultID, 
      Name, 
      Value, 
      RowNumber = ROW_NUMBER() OVER(PARTITION BY SearchResultID ORDER BY SearchresultItemID) 
    FROM SearchResultItem 
), Items AS 
( SELECT SearchResultID, 
      Name1 = MIN(CASE WHEN RowNumber = 1 THEN Name END), 
      Value1 = MIN(CASE WHEN RowNumber = 1 then Value END), 
      Name2 = MIN(CASE WHEN RowNumber = 2 THEN Name END), 
      Value2 = MIN(CASE WHEN RowNumber = 2 then Value END), 
      Name3 = MIN(CASE WHEN RowNumber = 3 THEN Name END), 
      Value3 = MIN(CASE WHEN RowNumber = 3 then Value END), 
      Name4 = MIN(CASE WHEN RowNumber = 4 THEN Name END), 
      Value4 = MIN(CASE WHEN RowNumber = 4 then Value END) 
    FROM RankedItem 
    GROUP BY SearchResultID 
) 

SELECT SearchResult.SearchResultID, 
     SearchResult.ProductID, 
     SearchResult.SearchQuery, 
     SearchResult.WebsiteName, 
     SearchResult.URL, 
     SearchResult.IsFound, 
     SearchResult.CreatedOn, 
     SearchResult.BatchID, 
     SearchResult.Name, 
     Items.Name1, 
     Items.Value1, 
     Items.Name2, 
     Items.Value2, 
     Items.Name3, 
     Items.Value3, 
     Items.Name4, 
     Items.Value4 
FROM SearchResult 
     INNER JOIN Items 
      ON SearchResult.SearchResultID = Items.SearchResultID; 

Example on SQL Fiddle

如果你想返回一個可變數量的值,那麼你就需要使用動態SQL:

DECLARE @SQL NVARCHAR(MAX) = ''; 

SELECT @SQL = @SQL + ',[Name' + rn + '], [Value' + rn + '] ' 
FROM ( SELECT DISTINCT 
        rn = CAST(ROW_NUMBER() OVER(PARTITION BY SearchResultID ORDER BY SearchresultItemID) AS VARCHAR) 
      FROM SearchResultItem 
     ) p; 

SET @SQL = 'WITH RankedItem AS 
      ( SELECT SearchResultItemID, 
         SearchResultID, 
         Name, 
         Value, 
         RowNumber = ROW_NUMBER() OVER(PARTITION BY SearchResultID ORDER BY SearchresultItemID) 
       FROM SearchResultItem 
      ), UnPivoted AS 
      ( SELECT upvt.SearchResultID, 
         Name = upvt.n + CAST(RowNumber AS VARCHAR), 
         upvt.v 
       FROM RankedItem 
         UNPIVOT 
         ( n 
          FOR v IN ([Name], [Value]) 
         ) upvt 
      ), Pivoted AS 
      ( SELECT * 
       FROM UnPivoted 
         PIVOT 
         ( MAX(V) 
          FOR Name IN (' + STUFF(@SQL, 1, 1, '') + ') 
         ) pvt 
      ) 
      SELECT SearchResult.SearchResultID, 
        SearchResult.ProductID, 
        SearchResult.SearchQuery, 
        SearchResult.WebsiteName, 
        SearchResult.URL, 
        SearchResult.IsFound, 
        SearchResult.CreatedOn, 
        SearchResult.BatchID, 
        SearchResult.Name' + @SQL + '      
      FROM SearchResult 
        INNER JOIN Pivoted 
         ON SearchResult.SearchResultID = Pivoted.SearchResultID;'; 

EXECUTE SP_EXECUTESQL @SQL; 

Example on SQL Fiddle

NB我有意使用一種不同的方法在動態sql中做這件事,只是爲了顯示有多種方式來實現組合行的結果。