简体   繁体   中英

How to use rank() over PARTITION BY in Mysql

Let's consider that there are three material types such as ('COTTON', 'LEATHER', 'SILK') and I want to fetch the dress_id's which has all theses three material types. I want to rank them as well.

Can someone explain step by step on how to do this ? I came through few examples and none of them seems to be clear to me.

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

I get an error in MYSQL work bench while executing this query. Error Code: 1305. FUNCTION rank does not exist.

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

In earlier versions of MySQL, you can either use variables or a correlated subquery.

Because you have only a handful of materials for each dress, a correlated subquery is reasonable, particularly with the right index. The code looks like:

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;

Note that this implements the logic based on your data not the query. The corresponding query would be:

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

The index that you want is on dress_types(dress_id, last_updated_date) .

Actually, these are the same so long as there are no duplicates (by date). The logic may be different if there are duplicates.

SELECT dress_id
     , material
     , LAST_UPDATED_DATE
   rank() over(PARTITION BY dress_id ORDER by LAST_UPDATED_DATE asc) as rank
FROM dress_types
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

The inner select selects dresses that have existence of all 3 materials and ordered by dress_id, last_updated_date. The outer joins it with a prev_dress_id variable that can be set at the end of each row. The the logics in case statement to calculate rank based on @prev_dress_id != or = T.dress_id. sqlfiddle

For previous versions of MySQL 8.0 you must use variables to simulate the ranking:

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

See the demo .
Results:

| 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    |

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM