【问题标题】:SQL order by needs to check if DATETIME2 is not null then return them first and after order by idSQL order by 需要检查 DATETIME2 是否不为空,然后先返回它们,然后在 order by id
【发布时间】:2020-03-10 15:41:41
【问题描述】:

我有两张桌子,我无法弄清楚如何按语句进行排序以满足我的需要。 基本上,如果FeaturedUntil 列大于现在,那么这些应该首先由PurchasedAt 列排序返回。最近的购买应该是第一个。在这些之后,所有内容都应按项目Id 列降序排序。

创建表格脚本

create table Items(
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [Name] nvarchar(200) null,
) 

create table Feature(
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [PurchasedAt] [datetime2](7) NOT NULL,
    [FeaturedUntil] [datetime2](7) NOT NULL,
    [ItemId] [int] NOT NULL,
)

插入脚本

insert into Items(Name) values ('test1')
insert into Feature(PurchasedAt, FeaturedUntil, ItemId) values (dateadd(day, -3, getdate()), dateadd(month, 1, getdate()), @@IDENTITY)
insert into Items(Name) values ('test2')
insert into Feature(PurchasedAt, FeaturedUntil, ItemId) values (dateadd(day, -2, getdate()), dateadd(month, 1, getdate()), @@IDENTITY)
insert into Items(Name) values ('test3')
insert into Feature(PurchasedAt, FeaturedUntil, ItemId) values (dateadd(day, -1, getdate()), dateadd(month, -1, getdate()), @@IDENTITY)
insert into Items(Name) values ('test4')

选择脚本

select * 
from Items i 
left join Feature f on i.Id = f.ItemId
order by 
case when f.FeaturedUntil is not null THEN f.PurchasedAt
else  i.Id 
end

select 应该首先返回 test2,因为它的 FeaturedUntil 比现在大,并且是最近购买的,第二行应该是 test1,因为它是在 test2 之前购买的。在这之后应该是test4,最后一个是test3,因为它们没有加入Feature表数据或者FeatureUntil不大于现在,它们是按Item.Id降序排列的。

【问题讨论】:

    标签: sql sql-server


    【解决方案1】:

    根据您告诉我们的内容,我认为这可能就是您所追求的:

    ORDER BY CASE WHEN FeaturedUntil > GETDATE THEN PurchasedAt ELSE '99991231' END ASC, --Future features first, and in date order
                                                                                         --(past have a silly in future date, so always last
             Id; --Then ID
    

    【讨论】:

    • 按预期工作,@Sugafree。 db<>Fiddle。如果你不解释原因,我帮不了你。
    • 感谢您的帮助 Larnu。之所以我不解释,是因为肖恩已经答对了。 FeaturedUntil 大于现在的商品应按降序排列,这意味着最近购买的商品应排在第一位(test2)。你的排序是升序的,Id 列的顺序也不正确。我在问题中已经解释过了,正确的结果顺序应该是test2, test1, test4, test3
    • 这不是您在问题中所说的,实际上,@Sugafree :"应该由 PurchasedAt 列首先订购返回。最近的购买应该是第一个。 这实际上并不意味着降序或升序。未来日期可能会排在*之前过去日期。这实际上是当前日期和时间与列日期之间的绝对值。跨度>
    • 我明白你的意思了,Larnu,“最近到现在”的意思是 desc 的过去和 asc 的未来日期项目。我认为令人困惑的是,OP 的“最新”意味着最新到最旧,而您从字面上理解它是绝对值概念。我回答的时候根本没想到!
    【解决方案2】:

    试试下面的。

    select *,  case when f.FeaturedUntil is not null THEN f.PurchasedAt else NULL end AS PurchasedAtNew
    from Items i 
    left join Feature f on i.Id = f.ItemId
    order by PurchasedAtNew desc, i.Id
    

    【讨论】:

      【解决方案3】:
      SELECT *
      FROM   items i
             LEFT JOIN feature f
                    ON i.id = f.itemid
      ORDER  BY CASE
                  WHEN f.featureduntil > getdate THEN purchasedat
                  ELSE '19000101'
                END DESC,
                id DESC
      

      您需要按降序排序,以便首先获得最近的购买; ID 排序仍会发生,因此如果您有两个相同的 PurchasedAt,它将按 ID 对这 2 个进行排序。

      【讨论】:

      • Id 也需要按降序排列,但 PurchasedAt 永远不会相同,因此如果您将 Id desc 放在末尾,它会返回正确的结果。
      • 对不起,我错过了 - 你是对的,你确实要求 ID desc 但正如你所说,添加 DESC 将解决这个疏忽。我会为后代编辑答案:)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-10-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-12-31
      • 1970-01-01
      • 2012-03-07
      相关资源
      最近更新 更多