两个日期列按特殊逻辑排序

Posted

技术标签:

【中文标题】两个日期列按特殊逻辑排序【英文标题】:Two date column ordering according to special logic 【发布时间】:2021-10-20 15:38:02 【问题描述】:

我需要一些帮助才能通过查询获得以下所需顺序,我已在下面硬编码所需顺序。如果日期列为空但优先考虑 [date] 其中不为空,我需要按列日期或创建日期排序,如下所示

Create Date Date Desired Order
2017-01-01 14:09:00.000 NULL 1
2017-01-01 14:10:03.000 2019-01-01 00:00:00.000 2
2017-01-01 14:10:04.000 NULL 3
2017-01-01 14:10:02.000 2020-01-01 00:00:00.000 4
2017-01-01 14:10:00.000 2021-01-01 00:00:00.000 5
drop table if exists #a

create table #a(
    create_date datetime,
    [date] datetime,
    [desired_order] int,
    primary key ([create_date])
);

insert into #a values('20170101 14:09:00.000', NULL,  1);
insert into #a values('20170101 14:10:00.000', '20210101',5);
insert into #a values('20170101 14:10:03.000', '20190101', 2);
insert into #a values('20170101 14:10:04.000', NULL, 3);
insert into #a values('20170101 14:10:02.000', '20200101', 4);

select * from #a order by desired_order

来自 cmets 的进一步解释:首先,我想按 create_date 排序,但任何出现乱序的日期值,即较新的日期出现在较早的行中,那么它需要是移动到结果集的末尾以及按日期排序的任何此类行。

接受答案后:我发现一组数据破坏了接受的解决方案:

insert into #a(create_date, [date]) values('20170101 14:09:00.000', NULL);
insert into #a(create_date, [date]) values('20170101 14:10:00.000', '20210101');
insert into #a(create_date, [date]) values('20170101 14:10:05.000', '20180101');
insert into #a(create_date, [date]) values('20170101 14:10:03.000', '20160101');
insert into #a(create_date, [date]) values('20170101 14:10:02.000', '20160205');
insert into #a(create_date, [date]) values('20170101 14:10:04.000', NULL);
insert into #a(create_date, [date]) values('20170101 14:10:01.000', '20200101');
insert into #a(create_date, [date]) values('20170101 14:10:06.000', '20230101');
insert into #a(create_date, [date]) values('20170101 14:10:07.000', '20170101');

由于某种原因,2017 年早于 2016 年,感谢您的帮助。

通过所有测试用例的解决方案:

;WITH cte1 AS (
    SELECT 
        create_date, 
        [DATE],
        ROW_NUMBER() OVER(ORDER BY CREATE_DATE) CN,
        ROW_NUMBER() OVER(ORDER BY [DATE]) DN
  FROM #a
)
select *
from 
    cte1
order by 
    case when [date] is null then CN else DN end, 
    CREATE_DATE

【问题讨论】:

ISNULL/COALESCE 有什么问题? order by coalesce([date],[create_date]) 将首先显示两个空日期行,这不是我想要的,请参阅上表。 你能解释一下为什么像 2019-01-01 00:00:00.000 这样的日期是第二个吗? “如果日期列为空,我需要按日期列或创建日期排序,如下所示”,但以下数据不符合该要求。如果是这样,第 2 行就不是第 2 行,而是第 3 行。 他们复制粘贴了您评论的内容,这不是他们自己的话(我认为这在某些方面没有真正帮助)但我重新打开了@DaleK。 【参考方案1】:

这似乎是一个非常奇怪的要求。您可以使用min 解析函数来解决这个问题,以找出我们前面是否有更小的date 值。这是一个可能的解决方案,用 cmets 来解释逻辑:

with cte1 as (
  select *
    -- Find the smallest value between this row and the last row
    , min([Date]) over (partition by case when [date] is not null then 1 else 0 end order by create_date desc rows between unbounded preceding and unbounded following) mindate
  from #a
)
select create_date, [date]
  -- Testing - uncomment to see how the logic works
  --, desired_order, mindate
from cte1
-- If no date, always keep in the first section, and order by create_date
-- If there is a date, check whether this date is greater than the smallest date ahead of us, and if so move ahead
order by case when [date] is null then 0 else case when [date] > [mindate] then 1 else 0 end end, case when [date] > [mindate] then [date] else create_date end;

返回:

create_date date
2017-01-01 14:09:00.000 NULL
2017-01-01 14:10:03.000 2019-01-01 00:00:00.000
2017-01-01 14:10:04.000 NULL
2017-01-01 14:10:02.000 2020-01-01 00:00:00.000
2017-01-01 14:10:00.000 2021-01-01 00:00:00.000

注意:由于您的示例数据非常简短,因此我无法确定此功能是否适用于所有边缘情况。

【讨论】:

你是对的,我发现一组数据打破了公认的逻辑,我已经更新了问题,感谢你的帮助。 嗨,很抱歉让您感到痛苦,但发现另一个问题,请参阅更新的“接受答案后”插入数据 @Alex 两件事,不断改变球门柱是一种非常糟糕的形式。您需要确保您提出的任何问题提前涵盖所有边缘情况。其次,我为您提供了一个很好的起点……与其要求我调整此查询以满足您的新数据,不如自己动手并理解逻辑以及如何调整它以满足您的新要求。您还缺少新数据集中所需的顺序。

以上是关于两个日期列按特殊逻辑排序的主要内容,如果未能解决你的问题,请参考以下文章

sql 日期正序 时间倒序

Pandas groupby 多列基础日期列按纪元周

MySQL 从两列按值排序

excel分组,将A列按名称分组之后,B列再次内嵌分组,C列再次内嵌,怎么弄?很急!!!

将来自两个不同 wordpress 的帖子合并到一个按日期排序的帖子页面

问SQL,按日期和时间两个字段排序?