如何通过交替(0,0,0,1,1,1,1,1,1,0,0,0,...)行来排序结果

时间:2019-09-03 07:17:36

标签: mysql sql

我正在使用MySQL执行数据库事务,并使用PHP运行MySQL查询。我想按以下顺序使用stack1列的值(0、0、0、1、1、1、1、1、1、0、0、0,...)来获取查询结果。我想按where列的值按3:6的比例获取记录。

有没有办法实现这一目标?

我搜索了不同的算法,但没有找到符合我要求的内容。我找到了唯一一个由替代记录引发结果的查询,但是我的要求没有得到满足。

我希望输出类似

function readDocuments(collection, options = {}) {
    let {where, orderBy, limit} = options;
    let query = firebase.firestore().collection(collection);

    if (where) {
        if (where[0] instanceof Array) {
            // It's an array of array
            for (let w of where) {
                query = query.where(...w);
            }
        } else {
            query = query.where(...where);
        }

    }

    if (orderBy) {
        query = query.orderBy(...orderBy);
    }

    if (limit) {
        query = query.limit(limit);
    }

    return query
            .get()
            .then()
            .catch()
    }

// Usage
// Multiple where
let options = {where: [["category", "==", "someCategory"], ["color", "==", "red"], ["author", "==", "Sam"]], orderBy: ["date", "desc"]};

//OR
// A single where
let options = {where: ["category", "==", "someCategory"]};

let documents = readDocuments("books", options);

3 个答案:

答案 0 :(得分:1)

您需要与ROW_NUMBER() OVER (PARTITION BY is_free ORDER BY id)类似的内容。一旦有了每个分区的行号(例如0-0、0-1、0-2、0-3,...,1-0、1-1、1-2、1-3,... ),您可以使用基本数学对结果进行排序(值0-0 ... 0-2和1-0 ... 1-5排在最前面,0-3 ... 0-5和1-6 ... 1-11排名第二,依此类推。不幸的是,MySQL 5.x不支持窗口函数,因此您需要使用某种技巧来计算行数。这是一个:

SELECT *
     , rn div IF(is_free = 1, 6, 3) AS gn
FROM (
    SELECT id
         , is_free
         , (SELECT COUNT(*) FROM t AS x WHERE x.id < t.id AND x.is_free = t.is_free) AS rn
    FROM t
) AS x
ORDER BY gn, is_free

Demo on db<>fiddle

答案 1 :(得分:0)

在MySQL 8+中,您可以使用:

order by floor( (row_number() over (partition by is_free order by id) - 1) / 4),
         is_free, id

row_number()上的算术将它们分批处理。您可以对早期版本中的变量执行类似的操作:

select t.id, t.is_free
from (select t.*,
             (@rn := if(@if = is_free, @rn + 1,
                        if(@if := is_free, 1, 1)
                       )
             ) as rn
      from (select t.* from t order by is_free, id) t cross join
           (select @if := -1, @rn := 0) params
     ) t
order by floor((rn - 1) / 4), is_free, id;

答案 2 :(得分:0)

select id,is_free,rank
from (
         (
            select id,is_free,if(@row_num = @target,@target := @target + 9,@target := @target + 0) as target,if(@target - @row_num > 3,@row_num := @row_num + 7,@row_num := @row_num + 1) as rank
            from test,(select @row_num := 0,@target := 3) t2
            where is_free = 0
         )
        union
          (
            select id,is_free,if(@row_num2 = @target2,@target2 := @target2 + 9,@target2 := @target2 + 0) as target,if(@target2 - @row_num2 > 8,@row_num2 := @row_num2 + 4,@row_num2 := @row_num2 + 1) as rank
            from test,(select @row_num2 := 3,@target2 := 9) t3
            where is_free = 1
          )
) derived
order by rank,is_free,id;

演示: https://www.db-fiddle.com/f/pc9oCwwtWjacETVeGCMtcw/0

  • 上面的想法是给每行rank,使我们可以保持3:6的比率。

  • 如果我们仔细观察,0遵循一系列1 , 2 , 3 , 10 , 11 , 12 , 19 , 20 , 211遵循一系列4, 5, 6, 7, 8, 9, 13, 14, 15, 16, 17, 18, 22, 23 ...,如下所示:

系列:

0   0   0   1   1   1   1   1   1   0   0   0   1   1   1   1   1   1   0   0   0

1   2   3   4   5   6   7   8   9  10   11  12  13  14  15  16  17  18  19  20  21  
  • 因此,在上述查询中,我们首先获取0的所有记录,并以上述方式从1开始为其分配行号。然后,通过分配从1开始的行号,以相同的方式获取is_free = 4的所有记录。

  • 最后,我们使用并集合并两个结果并按其排名对其进行排序。