MySQL结果集按固定位置排序

Seb*_*zak 6 php mysql

我有跟随,简单的表

Item (id, name, date, fixed_position)

(1, 'first entry', '2016-03-09 09:00:00', NULL)
(2, 'second entry', '2016-03-09 04:00:00', 1)
(3, 'third entry', '2016-03-09 05:00:00', NULL)
(4, 'fourth entry', '2016-03-09 19:00:00', NULL)
(5, 'fifth entry', '2016-03-09 13:00:00', 4)
(6, 'sixth entry', '2016-03-09 21:00:00', 2)
Run Code Online (Sandbox Code Playgroud)

物品的数量不固定,实际上可以在~100到~1000之间变化.

我想要实现的是执行查询以返回按date字段排序的项目集合,该fixed_position字段考虑字段,其代表类似"固定"结果到特定位置的内容.如果fixed_position给定条目不为NULL,则结果应固定到第n个位置,如果fixed_position为NULL,ORDER BY则应优先.

期望的查询输出更明亮的解释:

(2, 'second entry', '2016-03-09 04:00:00', 1)    // pinned to 1-st position
(6, 'sixth entry', '2016-03-09 21:00:00', 2)     // pinned to 2-nd position
(3, 'third entry', '2016-03-09 05:00:00', NULL)  // ORDER BY `date`
(5, 'fifth entry', '2016-03-09 13:00:00', 4)     // pinned to 4-th position
(1, 'first entry', '2016-03-09 09:00:00', NULL)  // ORDER BY `date`
(4, 'fourth entry', '2016-03-09 19:00:00', NULL) // ORDER BY `date`
Run Code Online (Sandbox Code Playgroud)

我已经尝试过在订购MySql结果时发布的解决方案,当某些项目有固定位置但是即使使用复制粘贴方法,这似乎根本不起作用.

我到目前为止尝试的是这个查询:

SELECT
  @i := @i +1 AS iterator,
  t.*,
  COALESCE(t.fixed_position, @i) AS positionCalculated
FROM
  Item AS t,
  (
SELECT
  @i := 0
) AS foo
GROUP BY
  `id`
ORDER BY
  positionCalculated,
  `date` DESC
Run Code Online (Sandbox Code Playgroud)

哪个回报:

iterator | id | name        | date                | fixed_position | positionCalculated 
1          1    first entry   2016-03-09 09:00:00   NULL             1
2          2    second entry  2016-03-09 04:00:00   1                1
6          6    sixth entry   2016-03-09 21:00:00   2                2
3          3    third entry   2016-03-09 05:00:00   NULL             3
4          4    fourth entry  2016-03-09 19:00:00   NULL             4
5          5    fifth entry   2016-03-09 13:00:00   4                4
Run Code Online (Sandbox Code Playgroud)

MySQL是否可以执行此类任务,还是应该采用后端方法并array_merge()在两个结果集上执行PHP ?

Gio*_*sos 3

解决这个问题的一个强力方法是首先创建一个计数表,其行数大于原始表:

SELECT @rn := @rn + 1 AS rn
FROM (
   SELECT 1 AS x UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1) AS t1
CROSS JOIN (   
   SELECT 1 AS x UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1) AS t2
CROSS JOIN (SELECT @rn := 0) AS v
Run Code Online (Sandbox Code Playgroud)

然后,您可以将此表左连接到包含原始表的所有固定位置的派生表:

SELECT Tally.rn
FROM (
   ... tally table query here 
) AS Tally
LEFT JOIN (
   SELECT fixed_position
   FROM Item
) AS t ON Tally.rn = t.fixed_position
WHERE t.t.fixed_position IS NULL
Run Code Online (Sandbox Code Playgroud)

以上返回待填补的缺失订单位置。

演示在这里

现在,您可以使用上述查询作为连接到原始表的另一个派生表,以实现所需的排序:

SELECT id, name, `date`, fixed_position, Gaps.rn, 
       derived.seq, Gaps.seq
FROM (
  SELECT id, name, `date`, fixed_position,
         @seq1 := IF(fixed_position IS NULL, @seq1 + 1, @seq1) AS seq
  FROM Item     
  CROSS JOIN (SELECT @seq1 := 0) AS v
  ORDER BY `date`
 ) AS derived
LEFT JOIN ( 
    SELECT Tally.rn,
           @seq2 := @seq2 + 1 AS seq
    FROM (
      SELECT @rn := @rn + 1 AS rn
      FROM (
        SELECT 1 AS x UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1) AS t1
      CROSS JOIN (   
        SELECT 1 AS x UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1) AS t2
      CROSS JOIN (SELECT @rn := 0) AS v
    ) AS Tally
    LEFT JOIN (
      SELECT fixed_position
      FROM Item
   ) AS t ON Tally.rn = t.fixed_position  
   CROSS JOIN (SELECT @seq2 := 0) AS v
   WHERE t.t.fixed_position IS NULL
   ORDER BY rn
 ) AS Gaps ON (derived.seq = Gaps.seq) AND (derived.fixed_position IS NULL)
 ORDER BY COALESCE(derived.fixed_position, Gaps.rn) 
Run Code Online (Sandbox Code Playgroud)

演示在这里