Oracle OR MySQL - 具有不同criterea的自定义ORDER,具体取决于NULL值

时间:2017-09-26 19:41:02

标签: mysql oracle

我有两对DATE的表。我想根据这些日期的时间来订购结果。每行至少一对日期(当一行有两个区间时:start2> start1,end2> end1和start2> = end1),如下所示:

      | start1 | end1 | start2 | end2
row 1 | 4:00   | 5:00 | 5:00   | 6:00
row 2 | 4:30   | 5:00 | NULL   | NULL
row 3 | NULL   | NULL | 5:30   | 6:00
row 4 | 5:00   | 6:00 | 6:00   | 7:00
  • 当两行都有两对时,应该用start1进行比较。

  • 当一行只有pair1而另一行只有pair2时,应将start1与start2进行比较

  • 当一行只有一对(任何)而另一对都有两对时,它们应该由第一行具有的对(start1到start1或start2到start2)进行比较。例如:如果第一行只有start2和end2,第二行有start1,end1,start2和end2,那么这两行应该只用start2进行比较(应忽略第二行的start1)

    < / LI>

我该如何实现?

修改

我可以在C#中轻松完成,但我需要在数据库中执行此操作。下面的代码如何在C#中起作用:

static void Main(string[] args)
{
    ...
    intervals.Sort(new IntervalComparer());
}
public class IntervalComparer : IComparer<Interval>
{
    public int Compare(Interval quadro1, Interval quadro2)
    {
        int result = 0;
        if (quadro1.start1 != null && quadro2.start1 != null)
            result = quadro1.start1.Value.CompareTo(quadro2.start1.Value);
        else if (quadro1.start2 != null && quadro2.start2 != null)
            result = quadro1.start2.Value.CompareTo(quadro2.start2.Value);
        else if (quadro1.start1 != null)
            result = quadro1.start1.Value.CompareTo(quadro2.start2.Value);
        else
            result = quadro1.start2.Value.CompareTo(quadro2.start1.Value);
        return result;
    }
}

2 个答案:

答案 0 :(得分:1)

你的逻辑存在缺陷。请考虑以下示例:

  | start1 | start2
a | 4:00   | 7:00  
b | 5:00   | NULL  
c | NULL   | 6:00  

对于该数据,使用您的逻辑将会是以下情况:

a < b (a.start1 = 4:00 < b.start1 = 5:00)
b < c (b.start1 = 5:00 < c.start2 = 6:00)
c < a (c.start2 = 6:00 < a.start2 = 7:00)

因此a < b < c < a也是&#34; true&#34;。但是如果你想要一个有意义的命令,那么< oprator应该是可传递的。这意味着如果a < b为TRUE且b < c为TRUE,则a < c也应为TRUE。但事实并非如此。

因此,您可以将这三行命名为[a, b, c][b, c, a][c, a, b]。对我而言,它没有意义。

如果您需要SQL解决方案,则应重新定义逻辑。我建议使用估计的(平均)差异(AVG(start2 - start1))来填充NULL。在我的例子中,平均差异是3小时。因此,b.start2将替换为b.start1 + 3 hours = 8:00c.start1将替换为c.start2 - 3 hours = 3:00。您现在可以按估计值排序。

MySQL示例:

select t.*
    , d.avg_diff
    , coalesce(time_to_sec(t.start1),  time_to_sec(t.start2) - d.avg_diff) as estimated1
    , coalesce(time_to_sec(t.start2),  time_to_sec(t.start1) + d.avg_diff) as estimated2
from my_table t
cross join (
    select avg(time_to_sec(start2) - time_to_sec(start1))
        as avg_diff
    from my_table
) d
order by estimated1, estimated2;

您当然可以在ORDER BY子句中使用估算表达式:

select t.*
from my_table t
cross join (
    select avg(time_to_sec(start2) - time_to_sec(start1))
        as avg_diff
    from my_table
) d
order by
    coalesce(time_to_sec(t.start1),  time_to_sec(t.start2) - d.avg_diff),
    coalesce(time_to_sec(t.start2),  time_to_sec(t.start1) + d.avg_diff);

演示:http://rextester.com/HHLT51865

使用原始数据进行演示:http://rextester.com/AMJIDT94457

答案 1 :(得分:0)

尝试使用IF function,它应该是以下内容:

SELECT if(start1 not is null, TIME(start1), TIME(start2) ) AS sortable_value
FROM your_table ORDER by sortable_value

您的整个逻辑可以像上面的查询一样进行简化。如果start1不为null,则基本上减少为,然后按时间排序,否则按start2的时间排序

如果我误解了某些内容,那么你可以添加另一个IF而不是TIME(start1)(相当于then分支)或代替TIME(start2)(相当于{{1 }})。