MySQL每组选择X行

时间:2014-12-22 20:20:16

标签: mysql greatest-n-per-group

我有一个非常复杂的查询,我需要为每个businessType选择前N个项目。有不同数量的businessTypes,因此UNION在这种情况下不会工作。如何编辑此选项以按等级排序的每个businessType选择前10项?

SELECT data_ID,title,distance,age_rank,age_rank * 10 AS rank,age,businessType
FROM 
(SELECT sd.data_ID,sd.title,p.radius,distance_scale,distance_decay,
    p.distance_unit*DEGREES(ACOS(COS(RADIANS(p.latpoint))*COS(RADIANS(sd.storeLat))*
    COS(RADIANS(p.longpoint - sd.storeLon))+SIN(RADIANS(p.latpoint))*
    SIN(RADIANS(sd.storeLat)))) AS distance,
    EXP(-POWER(GREATEST(DATEDIFF(CURDATE(),d.createDate)-scale,0),2)/
    ((-2*POWER(scale,2))/(2*LOG(decay)))) AS age_rank,sd.businessType,sd.store_ID,
    DATEDIFF(CURDATE(),d.createDate) AS age
    FROM search_data sd
    LEFT JOIN data d
    ON sd.data_ID = d.data_ID
    JOIN (
        SELECT 40.6812509 AS latpoint,-73.9809685 AS longpoint,50.0 AS radius,69.0
        AS distance_unit,5 AS scale,0.5 AS decay, 1 as distance_scale, 0.001 
        AS distance_decay
    ) AS p ON 1=1
    WHERE sd.storeLat
    BETWEEN p.latpoint  - (p.radius / p.distance_unit)
    AND p.latpoint  + (p.radius / p.distance_unit)
    AND sd.storeLon
    BETWEEN p.longpoint - (p.radius / (p.distance_unit * COS(RADIANS(p.latpoint))))
    AND p.longpoint + (p.radius / (p.distance_unit * COS(RADIANS(p.latpoint))))
    AND DATE(d.createDate) >= DATE_ADD(CURDATE(),INTERVAL -90 DAY)
) AS d
WHERE distance <= radius
AND businessType = 1
GROUP BY store_ID
ORDER BY rank DESC;

编辑: 我尝试了建议的方法,但似乎无法正常工作。以下是我尝试过的简化方法:

SELECT sd.title,sd.businessType
FROM search_data sd INNER JOIN (
    SELECT
    businessType,
    GROUP_CONCAT(data_ID ORDER BY createDate DESC) grouped_deal_ID
    FROM
    search_deals
    GROUP BY store_ID) businessType_max
ON sd.businessType = businessType_max.businessType
AND FIND_IN_SET(sd.data_ID,grouped_deal_ID) <= 10
ORDER BY sd.businessType ASC;

通过进一步测试,我得到了一个使用(http://www.erikhaselhofer.com/?p=1793)的简单版本:

SELECT RowNum,businessType,createDate
FROM(
SELECT IF(@businessType=businessType,@ctr:=@ctr+1,@ctr:=1) as RowNum, @businessType:=businessType as businessType,title,createDate
FROM search_data
JOIN (SELECT @ctr:=1) as a
ORDER BY businessType, createDate DESC) as b
WHERE RowNum in (1,2,3) AND businessType IN (1,2,3,4,5,6,7);

1 个答案:

答案 0 :(得分:0)

关于这个主题,我已经回答了几个问题,我从中学到了很多我从article引用的内容。

通常,我尝试实现以下内容:

SELECT columns
FROM myTable m
WHERE (
   SELECT COUNT(*)
   FROM myTable mc
   WHERE mc.columnToGroupBy = m.ColumnToGroupBy AND mc.orderColumn >= m.orderColumn
   ) <= numberIWantToGroup

虽然使用没有子查询的较小表更容易演示,但正如您在question中所看到的那样,在您的情况下看起来可能类似于这样:

SELECT myColumns
FROM myTableWithAllItsJoins m1
WHERE(
   SELECT COUNT(*)
   FROM myTableWithAllItsJoins m2
   WHERE m1.businessType = m2.businessType AND m1.rank >= m2.rank
   ) <= 10

这将为每个businessType选择前10名。