MS SQL-一对多关系-需要返回单行

MS SQL-一对多关系-需要返回单行,sql,sql-server,tsql,select,one-to-many,Sql,Sql Server,Tsql,Select,One To Many,我有以下表格- Search Result ---------------- SearchResultID PK ProductID FK SearchQuery WebsiteName URL IsFound CreatedOn BatchID Name SearchResultItem ----------------- SearchResultItemID PK SearchResultID FK Name Value 这些表具有一对多关系,因此一个搜索结果可以有多个搜索结果项 我可以

我有以下表格-

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

SearchResultItem
-----------------
SearchResultItemID PK
SearchResultID FK
Name
Value
这些表具有一对多关系,因此一个搜索结果可以有多个搜索结果项

我可以在这些表上做一个内部连接,但是很明显,每个搜索结果项都有一行。理想情况下,我希望每个搜索结果一行,例如

SearchResultID | ProductID | SearchQuery | WebsiteName | URL | IsFound | 
CreatedOn | BatchID | Name | SearchResultItemID | Name 1 | Value 1 | Name 2 | 
Value 2 | Name 3 | Value 3 |
这可能吗?如果是这样的话,有人能给我指出正确的方向吗?我想应该是这样的,只有在ms sql中-

您可以使用该函数在每个搜索结果中为每个搜索结果项赋予排名:

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;
然后,您可以将其连接回搜索结果表,提供完整查询:

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;

如果要返回数量可变的值,则需要使用动态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;

注意:我特意在动态sql中使用了一种不同的方法来实现这一点,只是为了说明有多种方法可以实现合并行的结果。

您可以使用该函数在每个搜索结果中为每个搜索结果项赋予一个等级:

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;
然后,您可以将其连接回搜索结果表,提供完整查询:

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;

如果要返回数量可变的值,则需要使用动态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;


注意:我特意在动态sql中使用了一种不同的方法来实现这一点,只是为了说明有多种方法可以实现合并行的结果。

有多种方法可以实现这一点。你事先知道你有多少结果或想要多少结果吗?您希望将每行的信息连接到一列中,还是希望每行有一个单独的列?您好@DavidSöderlund,理想情况下,我希望每行有一个单独的列,我还可以事先知道我需要的结果数量,例如,我知道这个查询将有3组名称/值。有很多方法可以做到这一点。你事先知道你有多少结果或想要多少结果吗?您希望将每一行的信息连接到一列中,还是希望每一行有一个单独的列?您好@DavidSöderlund,理想情况下,我希望每一行有一个单独的列,我还可以事先知道我需要的结果数,例如,我知道此查询将有3组名称/值。。