【问题标题】:Order By Month Name in Sql-Server在 Sql-Server 中按月份名称排序
【发布时间】:2016-04-22 07:06:36
【问题描述】:

我有一个名为会话的下表

SessionID   SessionName

100         August
101         September
102         October
103         November
104         December
105         January
106         May
107         June
108         July

我执行了以下查询,得到如下输出。

Select SessionID, SessionName 
From dbo.Session  

SessionID   SessionName
100         August
101         September
102         October
103         November
104         December
105         January
106         May
107         June
108         July

结果按会话 ID 排序。但我需要如下输出,

SessionID   SessionName 
106         May
107         June
108         July
100         August
101         September
102         October
103         November
104         December
105         January

如何在 sql-server 中实现这一点?感谢您的帮助

【问题讨论】:

  • 只有SessionName 还是也有某种日期值?
  • 有值列的创建日期。但它也不按顺序
  • 问题是:你要处理年终吗?一月是13,二月是14?如果您必须排序超过 12 个月怎么办?
  • 这是一个静态表。无论年份,它只有 12 个月
  • 不能解决问题...如果有一月,您不知道是必须在前面订购还是在末尾订购...跨度>

标签: sql sql-server tsql sql-order-by


【解决方案1】:

我会使用case 表达式,例如:

order by case SessionName when 'August' then 1
                          when 'September' then 2
                          ...
                          when 'Juty' then 12
         end

8 月有 1 个,因为“在应用程序逻辑中,会话以 8 月开始”,如果您想从 1 月开始并以 12 月结束,则很容易重新编号。

【讨论】:

  • case 语句在查询中看起来很长。除此以外的任何其他解决方案。例如:是否可以将月份名称转换为月份编号并根据它进行分组?
  • 可以使用 cte 的或派生的表。 (或者可能是一个存储过程/函数。)
  • 在应用程序逻辑中,会话从八月开始。
  • 按给出的语法错误顺序使用 case 表达式
  • 有吗?奇怪的是,这种语法在 ANSI SQL 中已经存在很长时间了。 (至少从 SQL-92 开始。)
【解决方案2】:

为了避免任何与文化相关的麻烦,您可以使用如下查询从 sys 语言中获取月份索引:

(我最终会从中创建一个 TVF 并传入 langid 作为参数)

SELECT ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) MyMonthIndex
        ,Mnth.value('.','varchar(100)') AS MyMonthName
FROM
(
    SELECT CAST('<x>' + REPLACE(months,',','</x><x>') + '</x>' AS XML) AS XmlData
    FROM sys.syslanguages
    WHERE langid=0
) AS DataSource
CROSS APPLY DataSource.XmlData.nodes('/x') AS The(Mnth)

结果

1   January
2   February
3   March
4   April
5   May
6   June
7   July
8   August
9   September
10  October
11  November
12  December

编辑:直接使用的 UDF(例如在 order by 中)

CREATE FUNCTION dbo.GetMonthIndexFromMonthName(@MonthName VARCHAR(100),@langId INT)
RETURNS INT
AS
BEGIN
    RETURN
    (
        SELECT MyMonthIndex
        FROM
        (
            SELECT CAST(ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS INT) MyMonthIndex
                  ,Mnth.value('.','varchar(100)') AS MyMonthName
            FROM
            (
                SELECT CAST('<x>' + REPLACE(months,',','</x><x>') + '</x>' AS XML) AS XmlData
                FROM sys.syslanguages
                WHERE langid=@langId
            ) AS DataSource
            CROSS APPLY DataSource.XmlData.nodes('/x') AS The(Mnth)
        ) AS tbl
        WHERE MyMonthName=@MonthName
    );
END
GO

SELECT dbo.GetMonthIndexFromMonthName('February',0)

【讨论】:

  • 我喜欢这个,我想知道是否可以稍微简化 CSV 拆分(或者 CTE 的性能是否更好?),但这很重要
  • @AdrianoRepetti,在大多数情况下,CTE 和内联子选择会导致相同的执行计划。有大量关于字符串拆分的讨论(SQL Server 2016 将带来这个 - 叹息! - 作为一个函数!)。对于短字符串,XML 方法非常好,只要您确定字符串部分中没有禁止字符(如&lt;&gt;&amp;)...
【解决方案3】:

我认为你可以这样做:

SELECT * FROM session 
ORDER BY MONTH(session.SessionName + ' 1 2014') 

部分:

MONTH(session.SessionName + ' 1 2014')

将返回 3 月 3 日,在这种情况下,您实际上不需要关心年份

【讨论】:

  • 不!你真的从不应该依赖依赖于文化的格式!试试这个:SET LANGUAGE GERMAN; SELECT MONTH('January 1 2014')
【解决方案4】:

尝试将CAST你的月份名称(SessionName)转换成DATETIME格式,就像这样

SELECT * FROM table
ORDER BY DATEPART(mm, CAST(SessionName + '1900' AS DATETIME)) asc

【讨论】:

  • 不!你真的从不应该依赖依赖于文化的格式!试试这个:SET LANGUAGE GERMAN; SELECT MONTH('January 2014')
【解决方案5】:

您可以将字符串月份转换为数字,并按月份形式按数字排序

SELECT SessionID, SessionName, DATEPART(MM, SessionName)
FROM dbo.Session
ORDER BY DATEPART(MM, SessionName)

否则,如果您有类似“DateCreation”列的内容,您可以执行类似的操作

SELECT SessionID, SessionName, MONTH(DateCreation)
FROM dbo.Session
ORDER BY MONTH(DateCreation)

【讨论】:

    【解决方案6】:

    试试这个 .. 我假设您希望当前日期的下个月是起点,所以我在脚本中使用“Month(GetDate()”,否则您可以硬编码为 4 以获得所需的结果

    Declare @Session Table (SessionID INT, SessionName Varchar(20))
    Insert Into @Session Values (100,'August'),(101,'September'),(102,'October'),(103,'November'),(104,'December')
    ,(105,'January'),(106,'May'),(107,'June'),(108,'July')
    
    
    Select * From @Session
            ORDER BY CASE WHEN Month(CAST('01-' + SessionName + ' 2016' AS DateTime)) - Month(GetDate()) <= 0 
                        THEN 12 + Month(CAST('01-' + SessionName + ' 2016' AS DateTime)) - Month(GetDate())
                        ELSE Month(CAST('01-' + SessionName + ' 2016' AS DateTime)) - Month(GetDate())  END      
    

    对于德语 .. 使用下面的脚本 .. 在此我使用 soundex 进行月份比较

    SET LANGUAGE GERMAN; 
    Declare @Session Table (SessionID INT, SessionName Varchar(20))
    Insert Into @Session Values (100,'August'),(101,'September'),(102,'October'),(103,'November'),(104,'December')
    ,(105,'January'),(106,'May'),(107,'June'),(108,'July')
    
    
    Select * From @Session S
            INNER JOIN 
            (SELECT Number + 1 as [MonthNumber],
                    DateName(mm,DATEADD(mm,Number,0)) as [MonthName]
                    FROM master..spt_values
                    WHERE Type = 'P' and Number < 12
            )M ON SoundEx(M.MonthName)=SoundEx(S.SessionName)   
    
            ORDER BY CASE WHEN [MonthNumber] - Month(GetDate()) <= 0 
                        THEN 12 + [MonthNumber] - Month(GetDate())
                        ELSE [MonthNumber] - Month(GetDate())  END    
    

    【讨论】:

    • 不!你真的从不应该依赖依赖于文化的格式!试试这个:SET LANGUAGE GERMAN; SELECT CAST('01-' + 'January' + ' 2016' AS DateTime)
    • Navee,我看到了你的编辑 :-) 这个问题可能是,目前你依赖于 SET 命令,你必须告别任何 ad-hoc SQL,没有内联函数,没有在视图中使用......
    • 看看这里select * from sys.syslanguages。 soundex 方法可能适用于类似的语言,但不可靠...
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-20
    • 2023-04-03
    • 2014-01-30
    • 1970-01-01
    • 1970-01-01
    • 2020-07-25
    相关资源
    最近更新 更多