mysql - 选择有限的重复列行

时间:2017-07-05 01:36:44

标签: mysql limit

我拥有什么

所以我正在运行这个声明:

SELECT
  i.id,
  i.item_id,
  v.item_to_map_id,
  i.date,
  COALESCE( SUM(CAST(CAST(v.score AS char) AS SIGNED)), 0 ) AS score
FROM item_to_map i
LEFT JOIN
  vote_item v
    ON i.id = v.item_to_map_id
GROUP BY
  i.id, i.item_id, i.date, v.item_to_map_id
ORDER BY
  item_id asc, score desc;

我得到了下表:

+----+---------+----------------+---------------------+-------+
| id | item_id | item_to_map_id | date                | score |
+----+---------+----------------+---------------------+-------+
|  1 |       1 |              1 | 2017-07-05 09:38:23 |     3 |
|  3 |       1 |              3 | 2017-07-05 09:38:23 |     0 |
|  2 |       1 |              2 | 2017-07-05 09:38:23 |    -1 |
|  4 |       2 |           NULL | 2017-07-05 09:38:23 |     0 |
|  5 |       2 |           NULL | 2017-07-05 09:38:23 |     0 |
|  6 |       2 |           NULL | 2017-07-05 09:38:24 |     0 |
+----+---------+----------------+---------------------+-------+

我尝试做的是根据某些排序选择重复item_id的前X个,例如得分或日期。

我尝试了什么

我查看了这个答案https://stackoverflow.com/a/1902167/6554121并尝试了修改后的版本:

SELECT
  i.id,
  i.item_id,
  v.item_to_map_id,
  i.date,
  COALESCE( SUM(CAST(CAST(v.score AS char) AS SIGNED)), 0 ) AS score
FROM item_to_map i
LEFT JOIN
  vote_item v
    ON i.id = v.item_to_map_id
WHERE
     (
          SELECT
               COUNT(*)
          FROM
               item_to_map i2
          WHERE
               i2.item_id = i.item_id
     ) < 3    
GROUP BY
 i.id, i.item_id, i.date, v.item_to_map_id
ORDER BY item_id asc, score desc;

然而,这不会给我带来任何结果

我的期望

如果按分数排序:

+----+---------+----------------+---------------------+-------+
| id | item_id | item_to_map_id | date                | score |
+----+---------+----------------+---------------------+-------+
|  1 |       1 |              1 | 2017-07-05 09:38:23 |     3 |
|  3 |       1 |              3 | 2017-07-05 09:38:23 |     0 |
|  4 |       2 |           NULL | 2017-07-05 09:38:23 |     0 |
|  5 |       2 |           NULL | 2017-07-05 09:38:23 |     0 |
+----+---------+----------------+---------------------+-------+

1 个答案:

答案 0 :(得分:1)

您可以使用模拟行号功能的会话变量来实现此目的:

SET @row_number = 0;
SET @item_id = 1;

SELECT t.id, t.item_id, t.item_to_map_id, t.date, t.score
FROM
(
    SELECT
        @row_number:=CASE WHEN @item_id = t.item_id
                          THEN @row_number + 1 ELSE 1 END AS rn,
        @item_id:=t.item_id AS item_id,
        t.id, t.item_to_map_id, t.date, t.score
    FROM
    (
        SELECT
            i.id,
            i.item_id,
            v.item_to_map_id,
            i.date,
            COALESCE( SUM(CAST(CAST(v.score AS char) AS SIGNED)), 0 ) AS score
        FROM item_to_map i
        LEFT JOIN vote_item v
            ON i.id = v.item_to_map_id
        GROUP BY
            i.id, i.item_id, i.date, v.item_to_map_id
    ) t
    ORDER BY
        t.item_id, t.score DESC
) t
WHERE t.rn <= 2    -- this restricts to the first two rows per item_id group
                   -- as ordered by the logic in your ORDER BY clause

据我所知,没有很好的方法来获取MySQL中组的第一个X记录,除非您的模式恰好碰巧每个组都有行号。使用上面的会话变量是处理这种情况的一种方法,性能甚至可能都很好。

在这里演示:

Rextester