7

我有这张桌子

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

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

谢谢。

4

2 回答 2

9

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

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

于 2009-08-30T04:55:30.177 回答
1

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

为每个组选择前 n 行 Arnie Rowland,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 解决方案(添加者: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 解决方案

--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:为每个组选择 TOP n 行

于 2013-07-27T04:07:36.590 回答