我发现了一些示例,说明如何从分组集中选择单个最旧/最新的行,但是从数据集中获取最旧的两行时遇到了问题。
这是我的示例表:
CREATE TABLE IF NOT EXISTS `orderTable` (
`customer_id` varchar(10) NOT NULL,
`order_id` varchar(4) NOT NULL,
`date_added` date NOT NULL,
PRIMARY KEY (`customer_id`,`order_id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
INSERT INTO `orderTable` (`customer_id`, `order_id`, `date_added`) VALUES
('1234', '5A', '1997-01-22'),
('1234', '88B', '1992-05-09'),
('0487', 'F9', '2002-01-23'),
('5799', 'A12F', '2007-01-23'),
('1234', '3A', '2009-01-22'),
('3333', '7FHS', '2009-01-22'),
('0487', 'Z33', '2004-06-23'),
('3333', 'FF44', '2013-09-11'),
('3333', '44f5', '2013-09-02');
此查询返回两行以上:
SELECT customer_id, order_id, date_added
FROM orderTable T1
WHERE (
select count(*) FROM orderTable T2
where T2.order_id = T1.order_id AND T2.date_added <= T1.date_added
) <= 2;
由于我不是在寻找单行,因此这不是标准的greatest-n-per-group
类型查询。
我错过了什么,我可以获得每个customer_id的前两个订单?
答案 0 :(得分:3)
最佳(即最佳性能)方法是在查询中使用用户定义变量。
SELECT tmp.customer_id, tmp.date_added
FROM (
SELECT
customer_id, date_added,
IF (@prev <> customer_id, @rownum := 1, @rownum := @rownum+1 ) rank,
@prev := customer_id
FROM orderTable t
JOIN (SELECT @rownum := NULL, @prev := 0) r
ORDER BY t.customer_id
) tmp
WHERE tmp.rank <= 2
ORDER BY customer_id, date_added
<强>结果:
| CUSTOMER_ID | DATE_ADDED |
|-------------|----------------------------------|
| 0487 | January, 23 2002 00:00:00+0000 |
| 0487 | June, 23 2004 00:00:00+0000 |
| 1234 | May, 09 1992 00:00:00+0000 |
| 1234 | January, 22 1997 00:00:00+0000 |
| 3333 | January, 22 2009 00:00:00+0000 |
| 3333 | September, 02 2013 00:00:00+0000 |
| 5799 | January, 23 2007 00:00:00+0000 |
小提琴here。
请注意,连接仅用于初始化变量。
答案 1 :(得分:3)
您的原始查询应该是(在子查询中使用customer_id)
SELECT customer_id, order_id, date_added
FROM orderTable T1
WHERE (
select count(*) FROM orderTable T2
where T2.customer_id = T1.customer_id AND T2.date_added <= T1.date_added
) <= 2;
您也可以使用变量:
SELECT customer_id, order_id, date_added FROM (
SELECT customer_id, order_id, date_added,
@rownum := if(@prev_cust = customer_id, @rownum + 1,1) as rn,
@prev_cust := customer_id cust_var
FROM orderTable T1,
(SELECT @rownum := 0) r,
(SELECT @prev_cust := '') c
order by customer_id, date_added
) o where o.rn < 3;
答案 2 :(得分:0)
这是另一种(故意不完整的)方法,尽管其他人可能对性能有所了解......
SELECT x.*
, COUNT(*) rank
FROM ordertable x
JOIN ordertable y
ON y.customer_id = x.customer_id
AND y.date_added <= x.date_added
GROUP
BY x.customer_id
, x.date_added;
答案 3 :(得分:0)
这应该产生你所追求的结果,但外部SELECT
不会是最有效的,因为它在派生表上进行过滤。
SELECT ranked.*
FROM (
SELECT ot.* ,
@rownum := IF( ot.customer_id = @previous , @rownum +1, 1 ) rank,
@previous := ot.customer_id
FROM orderTable ot,
(SELECT @rownum :=1, @previous := NULL) init
ORDER BY customer_id, date_added
) ranked
WHERE rank <=2