【问题标题】:SQL Query, Selecting 5 most recent in each groupSQL 查询,每组选择 5 个最近的
【发布时间】:2009-08-30 04:39:02
【问题描述】:

我有这张桌子

CREATE TABLE `codes` (
 `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
 `language_id` int(11) unsigned NOT NULL,
 `title` varchar(60) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
 `time_posted` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
 PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8

language_id 是指记录使用的语言。 我想做的是检索每种语言_id中最近的五个(ORDER BY time_posted DESC LIMIT 5)记录的列表。我可以在 PHP 中使用许多不同的 SQL 查询循环执行此操作,但我觉得有一种更简单的方法。

我得买一本关于 SQL 的书,哈哈。

谢谢。

【问题讨论】:

  • 什么SQL引擎?不幸的是,这很重要——SQL Standard、PostgreSQL、MS SQL Server、Oracle、IBM DB2 等等,有一种绝妙的方式来做你想做的事——但如果你坚持使用 MySQL,那么完美的解决方案正在运行每个好的关系数据库和根据标准本身都是不可用的,所以这是软糖和拼凑的时间(对于 MySQL 的课程来说是标准的——叹息)。那么它会是什么——地球上每一个像样的 SQL 实现,一方面,或者 MySQL,另一方面......?
  • @Alex:别拐弯抹角了——让我们知道您对 MySQL 的感受!不要把它装瓶。 ;-)

标签: sql mysql select sql-order-by greatest-n-per-group


【解决方案1】:

这是我在 MySQL 中解决这种“每组前 N 个”类型查询的方法:

SELECT c1.*
FROM codes c1
LEFT OUTER JOIN codes c2
  ON (c1.language_id = c2.language_id AND c1.time_posted < c2.time_posted)
GROUP BY c1.id
HAVING COUNT(*) < 5;

另见“How do I select multiple items from each group in a mysql query?

【讨论】:

  • 对不起,C1和C2是从哪里来的?
  • 请注意,如果time_posted 可以有联系,您可能会得到一些有趣的结果。让我知道这是否是一个问题,因为它也可以解决。
  • @BillKarwin,这对我有用(我有一个类似的用例),但我不明白为什么我必须写“HAVING COUNT(*)
  • @AlbertoSchiabel:如果您想要每种语言的前 5 名,那么根据定义,c1 的行通过条件,必须少于 其他 5 行具有更大的时间戳。自己试试吧:sqlfiddle.com/#!9/5a34d6/1/0
【解决方案2】:

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

为每个组选择前 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 Variable
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

【讨论】:

  • 请注意,不鼓励仅链接的答案,因此答案应该是搜索解决方案的终点(相对于另一个参考中途停留,随着时间的推移往往会变得陈旧)。请考虑在此处添加独立的概要,并保留链接作为参考。
猜你喜欢
  • 2021-02-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-04
  • 2016-04-09
  • 1970-01-01
  • 1970-01-01
  • 2011-09-09
相关资源
最近更新 更多