简体   繁体   English

如何使用 sql 查询对列表列表进行排序?

[英]How to sort a list of lists using a sql query?

Abstract question抽象问题

I have a sql-table that contains records in the following form:我有一个包含以下形式的记录的 sql 表:
(list_id, value) where the list_id is an Integer identifiing a specific list and the value is something that has an order. (list_id, value)其中list_id是一个 Integer 标识特定列表,并且value是具有顺序的东西。

I now struggle to write a sql query that returns all records of that table at first ordered by the rank the list has compared to the other lists and then ordered by the value .我现在很难编写一个 sql 查询,该查询返回该表的所有记录,首先按列表与其他列表比较的排名排序,然后按value排序。

The abstract problem is, that I want to sort a list of lists using sql.抽象的问题是,我想使用 sql 对列表进行排序。

Algorithm to compare two lists比较两个列表的算法

The algorithm to compare two lists is the following:比较两个列表的算法如下:

data CompareRes = FirstSmaller | FirstGreater | Equal deriving Show

compareLists :: Ord a => [a] -> [a] -> CompareRes
compareLists [] [] = Equal
-- Longer lists are considered to be smaller
compareLists _ [] = FirstSmaller
compareLists [] _ = FirstGreater
compareLists (x:xs) (y:ys) 
  | x < y = FirstSmaller
  | x > y = FirstGreater
  | otherwise = compareLists xs ys

Details细节

In my specific case the values are all Date s.在我的具体情况下,这些值都是Date So my table looks like this:所以我的表是这样的:

CREATE TABLE `list_date` (
  `list_id` INT  NOT NULL,
  `date`    DATE NOT NULL,
  PRIMARY KEY (`list_id`, `date`)
);

I'm using a mysql:8.0 database so a solution using WINDOW -functions is acceptable.我正在使用 mysql:8.0 数据库,因此使用WINDOW的解决方案是可以接受的。

Example例子

Data数据

INSERT INTO `list_date` VALUES
   (1, '2019-11-02'), (1, '2019-11-03'), (1, '2019-11-04'), (1, '2019-11-05'), (1, '2019-11-07'), (1, '2019-11-08'), (1, '2019-11-09'),
   (2, '2019-11-01'), (2, '2019-11-03'), (2, '2019-11-04'),
   (3, '2019-11-01'), (3, '2019-11-02'), (3, '2019-11-03'),
   (4, '2019-11-02'), (4, '2019-11-04'), (4, '2019-11-13'), (4, '2019-11-14'),
   (5, '2019-11-03'), (5, '2019-11-04'), (5, '2019-11-05'), (5, '2019-11-10'),
   (6, '2019-11-01'), (6, '2019-11-02'), (6, '2019-11-03'), (6, '2019-11-05');

Query询问

Where I really struggle is to create an expression that calculates the list_rank :我真正挣扎的地方是创建一个计算list_rank的表达式:

SELECT 
    `list_id`, 
    `date`,
    <PLEASE HELP> as `list_rank`
FROM 
    `list_date`
ORDER BY 
    `list_rank`, `date`;

Expected result预期结果

| list_id | date       | list_rank |
|---------|------------|-----------|
| 6       | 2019-11-01 | 1         |
| 6       | 2019-11-02 | 1         |
| 6       | 2019-11-03 | 1         |
| 6       | 2019-11-05 | 1         |
| 3       | 2019-11-01 | 2         |
| 3       | 2019-11-02 | 2         |
| 3       | 2019-11-03 | 2         |
| 2       | 2019-11-01 | 3         |
| 2       | 2019-11-03 | 3         |
| 2       | 2019-11-04 | 3         |
| 1       | 2019-11-02 | 4         |
| 1       | 2019-11-03 | 4         |
| 1       | 2019-11-04 | 4         |
| 1       | 2019-11-05 | 4         |
| 1       | 2019-11-07 | 4         |
| 1       | 2019-11-08 | 4         |
| 1       | 2019-11-09 | 4         |
| 4       | 2019-11-02 | 5         |
| 4       | 2019-11-04 | 5         |
| 4       | 2019-11-13 | 5         |
| 4       | 2019-11-14 | 5         |
| 5       | 2019-11-03 | 6         |
| 5       | 2019-11-04 | 6         |
| 5       | 2019-11-05 | 6         |
| 5       | 2019-11-10 | 6         |

or或者

预期结果的可视化表示

That image is the current live result my application produces.该图像是我的应用程序生成的当前实时结果。 Currently the sorting is implemented using Java.目前排序是使用 Java 实现的。

Edit编辑

After not receiving a better answer, I implemented a solution as suggested by @gordon-linoff:在没有收到更好的答案后,我按照@gordon-linoff 的建议实施了一个解决方案:

SELECT 
    `list_id`, 
    `date`
FROM 
    `list_date`
        INNER JOIN (
            SELECT `sub`.`list_id`,
            GROUP_CONCAT(`sub`.`date` ORDER BY `sub`.`date` SEPARATOR '')  as `concat_dates`
            FROM `list_date` as `sub`
            GROUP BY `sub`.`list_id`
        ) `all_dates` ON (`all_dates`.`list_id` = `list_date`.`list_id`)
ORDER BY 
    `all_dates`.`concat_dates`, `date`;

I've also created an SQL Fiddle - So you can play around with your solution.我还创建了一个SQL 小提琴- 所以你可以玩弄你的解决方案。

But this solution does not sort the lists as expected because longer lists are considered bigger than smaller lists.但是此解决方案不会按预期对列表进行排序,因为较长的列表被认为比较小的列表更大。

So I am still hoping to receive a solution that solves 100% of my requirements:)所以我仍然希望能收到一个解决我 100% 需求的解决方案:)

If I understand correctly, you can sort the lists by the dates concatenated together:如果我理解正确,您可以按连接在一起的日期对列表进行排序:

select ld.*
from list_date ld join
     (select list_id, group_concat(date) as dates
      from ld
      group by list_id
     ) ldc
     on ld.list_id = ldc.list_id
order by ldc.dates, ld.date;

Since it's for MySql 8 the window functions can be used for this (yay).由于它适用于 MySql 8,因此 window 函数可用于此(耶)。

Here's a query that first calculates some metrics, to use in the calculation of the ranking:这是一个首先计算一些指标的查询,用于计算排名:

SELECT 
 list_id, 
 `date`,
 DENSE_RANK() OVER (ORDER BY ListMinDate ASC, ListCount DESC, ListMaxDate, list_id) AS list_rank
FROM
(
  SELECT 
   list_id,
   `date`,
   COUNT(*) OVER (PARTITION BY list_id) AS ListCount,
   MIN(`date`) OVER (PARTITION BY list_id) AS ListMinDate,
   MAX(`date`) OVER (PARTITION BY list_id) AS ListMaxDate
  FROM list_date
) q
ORDER BY list_rank, `date`

A test on db<>fiddle heredb<>fiddle 的测试在这里

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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