2016-03-09 128 views
6

我有以下的,简单的表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) 

项目的数量是不固定的,其实可以改变从约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` 

我试图解决方案张贴在Ordering MySql results when having fixed position for some items但即使复制粘贴的方法这似乎并没有在所有的工作。

我已经试过这一步是这个查询:

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 

将返回:

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 

是否MySQL能够执行这样的任务,或者我应该采取后端的做法,并执行PHP两个的array_merge()结果集?

+0

什么是您正在使用的SQL?这样我们就可以看到你的尝试。 IE:按日期排序,ifnull(fixed_position,0)' –

+0

我在我的问题中添加了示例查询。花了超过5小时寻找答案,几乎没有结果。 –

+0

'fixed_position'是你表中的一个字段还是一个计算的字段? –

回答

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 

然后就可以离开加入这个表,以包含所有派生表您的原始表的固定位置:

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 

以上的回报待填充缺失的顺序位置。

Demo here

现在,您可以使用上面的查询作为另一个派生表连接到原来的表来实现所期望的顺序:

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) 

Demo here

+0

这是完美的!谢谢你,你已经节省了我的一天和无数的工作时间。 –

0

我有同样的问题(按日期排序+注入具有固定位置值的行)。上述解决方案似乎工作。但是你必须知道你的表有多少价值。行:

SELECT 1 AS x UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1

已经得到扩展,如果你有更多的行,因为临时表是短。在我的数据库中搜索了一些谷歌搜索结果和测试数据后,我发现了一个能够满足您需求的解决方案,并且能够理解我的想法。

SELECT * FROM (SELECT create_date, fixedposition, @rownum:[email protected] + 1 AS colposition, 1 AS majorEntry FROM myTable JOIN (SELECT @rownum:=0) r WHERE fixedposition IS NULL ORDER BY crdate DESC) AS orderedFixed UNION ALL (SELECT create_date, fixedposition, fixedposition AS colposition, 0 AS majorEntry FROM myTable WHERE fixedposition IS NOT NULL ORDER BY fixedposition ASC) ORDER BY colposition ASC, majorEntry

因此,这是它如何工作的:有两个SELECT语句。 第一个SELECT搜索没有固定位置的所有列,并按日期对它们进行排序。此外,它还使JOIN添加一个行计数器列。 第二个搜索具有固定位置的所有行并通过“colposition”返回排序。

两个select语句都被UNION ALL组合在一起。该联合会首先由ASCending colposition排序,并在第二步中通过majonEntry-value指示具有固定位置的行将放置在具有相同位置的其他行之前。