【问题标题】:SQL Server - SELECT TOP 5 rows for each FKSQL Server - 为每个 FK 选择前 5 行
【发布时间】:2010-11-29 20:28:03
【问题描述】:

我有以下查询,它查找与搜索匹配的前 5 个产品。每个产品都与一个商店

相关联

从产品中选择 TOP 5 * p, 商店 s WHERE p.ShopId = s.ShopId 和 p.ProductName 喜欢 '%christmas%'

我需要扩展它,以便它返回我 每个 Shop 中的 TOP 5 Products

谁能告诉我如何修改查询来实现这一点? - 即选择 每个 商店中匹配“%christmas%”的 TOP 5 产品(而不是当前显示在 所有 商店中匹配“%chrismas%”的 TOP 5 产品)。

【问题讨论】:

  • 请问什么数据库:MySQL、SQL Server 等?

标签: sql-server greatest-n-per-group


【解决方案1】:

您实际上缺少一个 ORDER BY 以使 TOP 有意义,或者任何基于 ROW_NUMBER 的解决方案都需要一个 ORDER BY。

SELECT
    *
FROM
    Shops s 
CROSS APPLY (
    SELECT TOP 5
        *
    FROM
        Products p
    WHERE
        p.ShopId = s.ShopId AND p.ProductName LIKE '%christmas%'
    ORDER BY --added on edit
        ???
) X

【讨论】:

  • 实际查询使用 FTE 进行全文搜索 - 按排名 (CONTAINSTABLE) 排序 - 为清楚起见,将其从示例中删除 :-)
  • 请记住,您需要为前 5 名的查询添加别名才能使其正常工作。例如交叉申请(选择前 5 名...)作为 p
【解决方案2】:

试试这个:

select * from (
    select *, rn = row_number() over (partition by s.ShopId order by p.ProductName)
    from Products p, Shops s 
    where p.ShopId = s.ShopId AND p.ProductName LIKE '%christmas%'
) a where a.rn <= 5

【讨论】:

    【解决方案3】:

    试试这个

    SELECT DISTINCT 
            A.Product_Group_code
            ,B.Sub_Product_Group_code
            ,A.Product_code
            ,A.Product_name
    FROM dbo.A A
        LEFT JOIN dbo.B B
            ON A.Product_code = B.Product_code
    WHERE  B.Product_code IN
                    (
                        SELECT TOP 5 E.Product_code
                        FROM dbo.A D
                            LEFT JOIN dbo.B E
                                ON D.Product_code = E.Product_code
                        WHERE E.Sub_Product_Group_code = B.Sub_Product_Group_code
                    )
            AND B.Sub_Product_Group_code IS NOT NULL
    ORDER BY B.Sub_Product_Group_code,A.Product_name
    

    【讨论】:

      【解决方案4】:

      这是我刚刚找到的一个很好的解决方案。

      为每个组选择前 n 行 阿尼罗兰,2008 年 3 月 13 日

      每个类别有多个行,并且希望 按价格仅选择每个类别的前两 (2) 行。 例如,从以下数据:

      RowID    Category    ID  Description     Price
      1    Pot     A1  Small Saucepan  21.50
      2    Pot     A2  1 Qt Saucepan   29.95
      3    Pot     A3  1.5 Qt Saucepan     33.95
      4    Pot     A4  Double Boiler   39.50
      5    Pot     A5  Stewpot     49.50
      6    Pot     A6  Pressure Cooker     79.95
      7    Pan     B1  8" Pie  6.95
      8    Pan     B2  8" Sq Cake  7.50
      9    Pan     B3  Bundt Cake  12.50
      10   Pan     B4  9x12 Brownie    7.95
      11   Bowl    C1  Lg Mixing   27.50
      12   Bowl    C2  Sm Mixing   17.50
      13   Tools   T1  14" Spatula     9.95
      

      想要的输出是:

      RowID    Category    ID  Description     Price
      11   Bowl    C1  Lg Mixing   27.50
      12   Bowl    C2  Sm Mixing   17.50
      9    Pan     B3  Bundt Cake  12.50
      10   Pan     B4  9x12 Brownie    7.95
      6    Pot     A6  Pressure Cooker     79.95
      5    Pot     A5  Stewpot     49.50
      13   Tools   T1  14" Spatula     9.95
      

      有几种方法可以实现所需的输出。 该演示提供了 SQL Server 2005 / SQL Server 2008 的解决方案, 然后是 SQL Server 2000 的解决方案。

      为两种解决方案创建示例数据

      -- Suppress data loading messages
      SET NOCOUNT ON
      
      -- Create Sample Data using a Table Varable
      DECLARE @MyTable table
         (  RowID         int   IDENTITY, 
            Category      varchar(5),
            [ID]          varchar(5),
            [Description] varchar(25),
            Price         decimal(10,2)
         )
      
      -- Load Sample Data
      
      INSERT INTO @MyTable VALUES ( 'Pot', 'A1', 'Small Saucepan', 21.50 )
      INSERT INTO @MyTable VALUES ( 'Pot', 'A2', '1 Qt Saucepan', 29.95 )
      INSERT INTO @MyTable VALUES ( 'Pot', 'A3', '1.5 Qt Saucepan', 33.95 )
      INSERT INTO @MyTable VALUES ( 'Pot', 'A4', 'Double Boiler', 39.50 )
      INSERT INTO @MyTable VALUES ( 'Pot', 'A5', 'Stewpot', 49.50 )
      INSERT INTO @MyTable VALUES ( 'Pot', 'A6', 'Pressure Cooker', 79.95 )
      INSERT INTO @MyTable VALUES ( 'Pan', 'B1', '8"" Pie', 6.95 )
      INSERT INTO @MyTable VALUES ( 'Pan', 'B2', '8"" Sq Cake', 7.50 )
      INSERT INTO @MyTable VALUES ( 'Pan', 'B3', 'Bundt Cake', 12.50 )
      INSERT INTO @MyTable VALUES ( 'Pan', 'B4', '9x12 Brownie', 7.95 )
      INSERT INTO @MyTable VALUES ( 'Bowl', 'C1', 'Lg Mixing', 27.50 )
      INSERT INTO @MyTable VALUES ( 'Bowl', 'C2', 'Sm Mixing', 17.50 )
      INSERT INTO @MyTable VALUES ( 'Tools', 'T1', '14"" Spatula', 9.95 )
      Return to Top
      

      SQL Server 2005 / SQL Server 2008 解决方案

      --Query to Retrieve Desired Data
      SELECT
         RowID,
         Category,
         [ID],
         [Description],
         Price
      FROM (SELECT
               ROW_NUMBER() OVER ( PARTITION BY Category ORDER BY Price DESC ) AS 'RowNumber',
               RowID,
               Category,
               [ID],
               [Description],
               Price
            FROM @MyTable
            ) dt
      WHERE RowNumber <= 2
      
      -- Results
      RowID Category  ID Description     Price
      11    Bowl      C1 Lg Mixing       27.50
      12    Bowl      C2 Sm Mixing       17.50
      9     Pan       B3 Bundt Cake      12.50
      10    Pan       B4 9x12 Brownie    7.95
      6     Pot       A6 Pressure Cooker 79.95
      5     Pot       A5 Stewpot         49.50
      13    Tools     T1 14" Spatula     9.95
      Return to Top
      

      使用 CTE 的 SQL Server 2005 / SQL Server 2008 解决方案 (添加:雅各布·塞巴斯蒂安)

      -- Define a CTE with the name "dt" 
      ;WITH dt AS (
           SELECT
               ROW_NUMBER() OVER ( PARTITION BY Category ORDER BY Price DESC ) AS 'RowNumber',
               RowID,
               Category,
               [ID],
               [Description],
               Price
            FROM @MyTable
      )
      -- and select the data from the CTE
      SELECT
         RowID,
         Category,
         [ID],
         [Description],
         Price
      FROM dt
      WHERE RowNumber <= 2
      
      -- Results
      RowID Category  ID Description     Price
      11    Bowl      C1 Lg Mixing       27.50
      12    Bowl      C2 Sm Mixing       17.50
      9     Pan       B3 Bundt Cake      12.50
      10    Pan       B4 9x12 Brownie    7.95
      6     Pot       A6 Pressure Cooker 79.95
      5     Pot       A5 Stewpot         49.50
      13    Tools     T1 14" Spatula     9.95
      Return to Top
      

      SQL 2000 解决方案

      --Query to Retrieve Desired Data
      SELECT DISTINCT
         RowID,
         Category,
         [ID],
         [Description],
         Price
      FROM @MyTable t1
      WHERE RowID IN (SELECT TOP 2
                         RowID
                      FROM @MyTable t2
                      WHERE t2.Category = t1.Category
                      ORDER BY Price DESC
                     )
      ORDER BY 
         Category,
         Price DESC
      
      -- Results
      RowID Category  ID Description     Price
      11    Bowl      C1 Lg Mixing       27.50
      12    Bowl      C2 Sm Mixing       17.50
      9     Pan       B3 Bundt Cake      12.50
      10    Pan       B4 9x12 Brownie    7.95
      6     Pot       A6 Pressure Cooker 79.95
      5     Pot       A5 Stewpot         49.50
      13    Tools     T1 14" Spatula     9.95
      

      发件人:Select the TOP n Rows For Each Group

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-09-21
        • 2013-04-04
        • 2018-06-14
        • 1970-01-01
        • 1970-01-01
        • 2017-07-28
        • 1970-01-01
        相关资源
        最近更新 更多