如何在Mysql中使用rank()而不是PARTITION BY

问题描述 投票:0回答:4

我们假设有三种材质类型,例如(“棉”、“皮革”、“丝绸”),我想获取具有这三种材质类型的 dress_id。我也想给他们排名。

有人可以逐步解释如何做到这一点吗? 我举了几个例子,但我似乎都不清楚。

The output should look something like

DRESS_ID   MATERIAL LAST_UPDATED_DATE RANK
111        COTTON   2019-08-29         1
111        SILK     2019-08-30         2
111        LEATHER  2019-08-31         3
222        COTTON   2019-08-29         1
222        SILK     2019-08-30         2
222        LEATHER  2019-08-31         3
222        LEATHER  2019-09-02         4

执行此查询时,MYSQL 工作台出现错误。 错误代码:1305。功能等级不存在。

SELECT dress_id,
       rank() over(PARTITION BY dress_id, material ORDER by LAST_UPDATED_DATE asc) as rank
FROM dress_types;

mysql sql window-functions dense-rank
4个回答
1
投票

在早期版本的 MySQL 中,您可以使用变量或相关子查询。

因为每件衣服只有少量材料,所以相关子查询是合理的,特别是在索引正确的情况下。 代码如下:

SELECT d.dress_id, d.material,
       (SELECT COUNT(*)
        FROM dress_types d2
        WHERE d2.dress_id = d.dress_id AND
              d2.last_updated_date <= d.last_updated_date
       ) as rank
FROM dress_types d;

请注意,这基于您的数据而不是查询来实现逻辑。 相应的查询将是:

SELECT dress_id,
       rank() over (PARTITION BY dress_id ORDER by LAST_UPDATED_DATE asc) as rank
FROM dress_types;

您想要的索引在

dress_types(dress_id, last_updated_date)

实际上,只要没有重复(按日期),这些都是相同的。 如果有重复,逻辑可能会不同。


0
投票

对于MySQL 8.0之前的版本,必须使用变量来模拟排名:

SET @rownum := 0;
SET @group_number := 0;
SELECT dress_id, material, last_updated_date, rank FROM (
SELECT @rownum := case 
  when @group_number = dress_id then @rownum + 1 
  else 1
end AS rank, dress_id, material, last_updated_date,
@group_number := dress_id  
FROM dress_types 
ORDER BY 
  dress_id, 
  FIELD(material, 'COTTON', 'SILK', 'LEATHER'), 
  last_updated_date 
) t

查看演示
结果:

| dress_id | material | last_updated_date   | rank |
| -------- | -------- | ------------------- | ---- |
| 111      | COTTON   | 2019-08-29 00:00:00 | 1    |
| 111      | SILK     | 2019-08-30 00:00:00 | 2    |
| 111      | LEATHER  | 2019-08-31 00:00:00 | 3    |
| 222      | COTTON   | 2019-08-29 00:00:00 | 1    |
| 222      | SILK     | 2019-08-30 00:00:00 | 2    |
| 222      | LEATHER  | 2019-08-31 00:00:00 | 3    |
| 222      | LEATHER  | 2019-09-02 00:00:00 | 4    |

0
投票
SELECT T.*,
  CASE WHEN @prev_dress_id != T.dress_id THEN @rank:=1
       ELSE @rank:=@rank+1 
  END as rank,
  @prev_dress_id := T.dress_id as set_prev_dress_id
FROM 
  (SELECT dress_id,material,last_updated_date
  FROM dress_types T1
  WHERE EXISTS (SELECT 1 FROM dress_types E1 WHERE E1.dress_id = T1.dress_ID AND E1.material = 'COTTON')
    AND EXISTS (SELECT 1 FROM dress_types E2 WHERE E2.dress_id = T1.dress_ID AND E2.material = 'SILK')
    AND EXISTS (SELECT 1 FROM dress_types E3 WHERE E3.dress_id = T1.dress_ID AND E3.material = 'LEATHER')
  ORDER BY dress_id asc,last_updated_date asc
  )T,(SELECT @prev_dress_id:=-1)V

内部选择选择存在所有 3 种材质的连衣裙,并按 dress_id、last_updated_date 排序。 外部将其与可在每行末尾设置的 prev_dress_id 变量连接起来。 case 语句中的逻辑根据 @prev_dress_id != 或 = T.dress_id 计算排名。 sqlfiddle


0
投票
SELECT dress_id
     , material
     , LAST_UPDATED_DATE
     , rank() over(PARTITION BY dress_id ORDER by LAST_UPDATED_DATE ASC) as rank
FROM dress_types
© www.soinside.com 2019 - 2024. All rights reserved.