SQL查询,在每个组中选择最近的5个

时间:2022-12-01 12:33:39

I have this table

我有这张桌子

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 refers to what language the record is in. What I would like to do is retrieve a list of the five most recent (ORDER BY time_posted DESC LIMIT 5) records in each language_id. I could do this in a loop within PHP with a number of different SQL queries but I feel there is a simpler way.

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

I've got to get a book on SQL, haha.

我必须得到一本关于SQL的书,哈哈。

Thanks.

2 个解决方案

#1


10  

Here's how I solve this "top N per group" type of query in MySQL:

以下是我在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;

See also "How do I select multiple items from each group in a mysql query?"

另请参阅“如何在mysql查询中从每个组中选择多个项目?”

#2


1  

Here is a great solution I just found.

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

Select the TOP n Rows For Each Group Arnie Rowland, March 13, 2008

选择2008年3月13日的每个组的前n行Arnie Rowland

There are Multiple Rows for Each Category, and there is a desire to SELECT ONLY the TOP two (2) Rows per Category by Price. For example, from the following data:

每个类别有多行,并且希望按价格选择每个类别的前两(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

The desired output is:

所需的输出是:

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

There are several methods to accomplish the desired output. This demonstration provides a Solution for SQL Server 2005 / SQL Server 2008 , and then a Solution for SQL Server 2000.

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

Create Sample Data for Both Solutions

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

-- 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 Solution

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

SQL Server 2005 / SQL Server 2008 Solution using a CTE (Added by: Jacob Sebastian)

使用CTE的SQL Server 2005 / SQL Server 2008解决方案(添加者:Jacob Sebastian)

-- 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 Solution

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

From: Select the TOP n Rows For Each Group

发件人:为每个组选择TOP n行

#1


10  

Here's how I solve this "top N per group" type of query in MySQL:

以下是我在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;

See also "How do I select multiple items from each group in a mysql query?"

另请参阅“如何在mysql查询中从每个组中选择多个项目?”

#2


1  

Here is a great solution I just found.

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

Select the TOP n Rows For Each Group Arnie Rowland, March 13, 2008

选择2008年3月13日的每个组的前n行Arnie Rowland

There are Multiple Rows for Each Category, and there is a desire to SELECT ONLY the TOP two (2) Rows per Category by Price. For example, from the following data:

每个类别有多行,并且希望按价格选择每个类别的前两(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

The desired output is:

所需的输出是:

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

There are several methods to accomplish the desired output. This demonstration provides a Solution for SQL Server 2005 / SQL Server 2008 , and then a Solution for SQL Server 2000.

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

Create Sample Data for Both Solutions

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

-- 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 Solution

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

SQL Server 2005 / SQL Server 2008 Solution using a CTE (Added by: Jacob Sebastian)

使用CTE的SQL Server 2005 / SQL Server 2008解决方案(添加者:Jacob Sebastian)

-- 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 Solution

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

From: Select the TOP n Rows For Each Group

发件人:为每个组选择TOP n行