简体   繁体   English

在 MSSQL 中按一列排序

[英]Order By One One Column in MSSQL

I Have the following SQL Tables:我有以下 SQL 表:

[Calendar] [日历]

[CalendarId]
[Name]

SAMPLE DATA:样本数据:

CalendarId  ResourceKey    Name
1           1              tk1-Room1
2           2              tk1-Room2
3           3              tk1-noentries

[CalendarEntry] [日历条目]

[CalendarId]
[CalendarEntryId]
[Start]
[End]

SAMPLE DATA:样本数据:

CalendarId  Start                            End
1           2019-11-18 16:00:00.0000000      2019-11-18 17:00:00.0000000
1           2019-11-19 16:00:00.0000000      2019-11-19 17:00:00.0000000
2           2019-11-25 16:00:00.0000000      2019-11-25 17:00:00.0000000
1           2019-11-25 17:00:00.0000000      2019-11-25 18:00:00.0000000

Expected output:预期输出:

Name             StartDate             EndDate                ResourceKey
tk1-Room1        2019-11-25 17:00:00   2019-11-25 17:00:00    1
tk1-Room2        2019-11-25 16:00:00   2019-11-25 17:00:00    2
tk1-noentries    NULL                  NULL                   3

I am trying to list all Calendar entries, with their corresponding Start(Most Recent) and End Times.我试图列出所有Calendar条目,以及它们相应的开始(最近)和结束时间。

I have the following code which is working partially:我有以下部分工作的代码:

SELECT Name,StartDate,ResourceKey FROM [Calendar].[dbo].[Calendar] CAL
LEFT JOIN(
    SELECT 
        CalendarId, 
        MAX(ENT.[Start]) as StartDate
    FROM [CalendarEntry] ENT
    GROUP BY CalendarId
    )
AS ST on CAL.CalendarId = ST.CalendarId

However, If i was to include that column, In my sub SELECT, EG:但是,如果我要包含该列,则在我的子 SELECT 中,EG:

    SELECT 
        CalendarId, 
        MAX(ENT.[Start]) as StartDate,
        ENT.[End] as endDate

I get the following error:我收到以下错误:

Column 'CalendarEntry.End' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.

However, including it in the GROUP BY now causes Multiple CalendarEntry Rows to come back for each Calendar..但是,现在将它包含在 GROUP BY 中会导致多个 CalendarEntry Rows 为每个日历返回。

What is the best way for me to grab the most recent row out of CalendarEntry which allows me access to all the columns?我从 CalendarEntry 中获取最新行的最佳方式是什么,它允许我访问所有列?

Thanks!谢谢!

This is a typical top 1 per group question.这是典型的每组前 1 个问题。

You can either use row_number() :您可以使用row_number()

select *
from (
    select 
        c.*,
        e.*,
        row_number() over(partition by c.CalendarId order by e.Start desc) rn
    from [Calendar].[dbo].[Calendar] c
    left join [CalendarEntry] e ON c.CalendarId = e.CalendarId
) t
where rn = 1

Or you can filter with a correlated subquery:或者您可以使用相关子查询进行过滤:

select c.*, e.*
from [Calendar].[dbo].[Calendar] c
left join [CalendarEntry] e 
    on c.CalendarId = e.CalendarId
    and c.Start = (
        select max(e1.Start) from [CalendarEntry] e where c.CalendarId = e1.CalendarId
    ) 

I am trying to list all Calendar entries, with their corresponding Start(Most Recent) and End Times.我试图列出所有日历条目,以及它们相应的开始(最近)和结束时间。

I interpret this as the most recent record from CalendarEntry for each CalendarId :我将此解释为CalendarEntry中每个CalendarId最新记录:

select ce.*
from CalendarEntry ce
where ce.StartDate = (select max(ce2.StartDate)
                      from CalendarEntry ce2
                      where ce2.CalendarId = ce.CalendarId
                     );

You can try OUTER APPLY too, however @GMB 's answer is a better approach from performance prospective您也可以尝试OUTER APPLY ,但是@GMB的答案是从性能角度来看更好的方法

SELECT Name,
       StartDate,
       EndDate,
       ResourceKey
FROM dbo.Calendar AS C
    OUTER APPLY
(
    SELECT TOP 1 *
    FROM dbo.CalendarEntry
    WHERE CalendarId = C.CalendarId
    ORDER BY StartDate DESC,
             EndDate DESC
) AS K;

You can also try LAST_VALUE / FIRST_VALUE (available in SQL Server 2012 and later) functions too, as below, , however again @GMB 's answer is a better approach from performance prospective:您也可以尝试LAST_VALUE / FIRST_VALUE (在 SQL Server 2012 及更高版本中可用)函数,如下所示,但是再次@GMB的答案是从性能角度来看更好的方法:

SELECT DISTINCT
       Name,
       LAST_VALUE(StartDate) OVER (PARTITION BY C.CalendarId
                                   ORDER BY StartDate,EndDate
                                   ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING),
       LAST_VALUE(EndDate) OVER (PARTITION BY C.CalendarId
                                 ORDER BY StartDate,EndDate
                                 ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING),
       ResourceKey
FROM dbo.Calendar AS C
    LEFT JOIN dbo.CalendarEntry
        ON CalendarEntry.CalendarId = C.CalendarId;

If you want to use FIRST_VALUE function, then you should rewrite the order by as below:如果要使用 FIRST_VALUE 函数,则应按如下方式重写顺序:

ORDER BY StartDate DESC,EndDate DESC

And you also you will not need to specify the ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING section而且您也不需要指定ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING部分

SELECT DISTINCT
       Name,
       FIRST_VALUE(StartDate) OVER (PARTITION BY C.CalendarId
                                   ORDER BY StartDate DESC,EndDate DESC),
       FIRST_VALUE(EndDate) OVER (PARTITION BY C.CalendarId
                                 ORDER BY StartDate DESC,EndDate DESC),
       ResourceKey
FROM dbo.Calendar AS C
    LEFT JOIN dbo.CalendarEntry
        ON CalendarEntry.CalendarId = C.CalendarId;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM