如何在SQL中创建序数(即“1st”“2nd”等)

时间:2015-05-11 16:32:28

标签: sql sql-server tsql

我最近在SSRS-2008标签中回复to this question,要求将日期中的日期号码更改为序号(即“1st”,“2nd”而不是“1”,“2”)。该解决方案涉及VB.Net功能。我很好奇如何在SQL中执行此任务(特别是t-sql和SQL Server),或者是否有一些内置支持。

所以这是一个场景:假设您已经为1000名参赛者组织了一个足球赛,并将结果放在一个包含名称和地点(正常数字)列的表格中。您希望创建一个查询,以查看序号中的用户名和位置。

10 个答案:

答案 0 :(得分:14)

这是一个适用于任何数字的可扩展解决方案。我认为其他人使用%100代表11,12,13,但我错了。

WITH CTE_Numbers
AS
(
    SELECT 1 num
    UNION ALL
    SELECT num + 1
    FROM CTE_Numbers
    WHERE num < 1000
)

SELECT  CAST(num AS VARCHAR(10))
        +
        CASE
            WHEN num % 100 IN (11,12,13) THEN 'th' --first checks for exception
            WHEN num % 10 = 1 THEN 'st'
            WHEN num % 10 = 2 THEN 'nd'
            WHEN num % 10 = 3 THEN 'rd'
            ELSE 'th' --works for num % 10 IN (4,5,6,7,8,9,0)
        END
FROM CTE_Numbers
OPTION (MAXRECURSION 0)

答案 1 :(得分:9)

您可以像在应用层中一样轻松地执行此操作:

DECLARE @myDate DATETIME = '2015-05-21';
DECLARE @day INT;
SELECT  @day = DAY(@myDate);
SELECT  CASE WHEN @day IN ( 11, 12, 13 ) THEN CAST(@day AS VARCHAR(10)) + 'th'
             WHEN @day % 10 = 1 THEN CAST(@day AS VARCHAR(10)) + 'st'
             WHEN @day % 10 = 2 THEN CAST(@day AS VARCHAR(10)) + 'nd'
             WHEN @day % 10 = 3 THEN CAST(@day AS VARCHAR(10)) + 'rd'
             ELSE CAST(@day AS VARCHAR(10)) + 'th'
        END

如果需要,您也可以将其置于标量函数中。

修改

对于您的示例,它将是:

SELECT  Name ,
        CASE WHEN Place IN ( 11, 12, 13 )
             THEN CAST(Place AS VARCHAR(10)) + 'th'
             WHEN Place % 10 = 1 THEN CAST(Place AS VARCHAR(10)) + 'st'
             WHEN Place % 10 = 2 THEN CAST(Place AS VARCHAR(10)) + 'nd'
             WHEN Place % 10 = 3 THEN CAST(Place AS VARCHAR(10)) + 'rd'
             ELSE CAST(Place AS VARCHAR(10)) + 'th'
        END AS Place
FROM    FootRaceResults;

答案 2 :(得分:4)

非常害怕:

with
  ArabicRomanConversions as (
    select *
      from ( values
        ( 0, '', '', '', '' ), ( 1, 'I', 'X', 'C', 'M' ), ( 2, 'II', 'XX', 'CC', 'MM' ), ( 3, 'III', 'XXX', 'CCC', 'MMM' ), ( 4, 'IV', 'XL', 'CD', '?' ),
        ( 5, 'V', 'L', 'D', '?' ), ( 6, 'VI', 'LX', 'DC', '?' ), ( 7, 'VII', 'LXX', 'DCC', '?' ), ( 8, 'VIII', 'LXXX', 'DCCC', '?' ), ( 9, 'IX', 'XC', 'CM', '?' )
        ) as Placeholder ( Arabic, Ones, Tens, Hundreds, Thousands )
      ),
  OrdinalConversions as (
    select *
      from ( values
        ( 1, 'st' ), ( 2, 'nd' ), ( 3, 'rd' ), ( 11, 'th' ), ( 12, 'th' ), ( 13, 'th' )
        ) as Placeholder2 ( Number, Suffix )
      ),
  Numbers as (
    select 1 as Number
    union all
    select Number + 1
      from Numbers
      where Number < 3999 )
  select Number as Arabic,
    ( select Thousands from ArabicRomanConversions where Arabic = Number / 1000 ) +
    ( select Hundreds from ArabicRomanConversions where Arabic = Number / 100 % 10 ) +
    ( select Tens from ArabicRomanConversions where Arabic = Number / 10 % 10 ) +
    ( select Ones from ArabicRomanConversions where Arabic = Number % 10 ) as Roman,
    Cast( Number as VarChar(4) ) + Coalesce( (
      select top 1 Suffix from OrdinalConversions where Number = Numbers.Number % 100 or Number = Numbers.Number % 10 order by Number desc ), 'th' ) as Ordinal
    from Numbers option ( MaxRecursion 3998 );

答案 3 :(得分:2)

您可以使用案例陈述,即

更新:考虑到TPhe提到的青少年,并稍微重构。

SELECT
    Name,
    CASE 
        WHEN Place in(11, 12, 13) then CAST(Place as VARCHAR(20)) + 'th'
        WHEN RIGHT(CAST(Place as VARCHAR(20)), 1) = '1' then CAST(Place as VARCHAR(20)) + 'st'
        WHEN RIGHT(CAST(Place as VARCHAR(20)), 1) = '2' then CAST(Place as VARCHAR(20)) + 'nd'
        WHEN RIGHT(CAST(Place as VARCHAR(20)), 1) = '3' then CAST(Place as VARCHAR(20)) + 'rd'
        ELSE CAST(Place as VARCHAR(20)) + 'th'  
    END as Place
FROM
    RunnerTable

答案 4 :(得分:2)

  DECLARE @Number int = 94
  SELECT 
    CONVERT(VARCHAR(10),@NUMBER) + CASE WHEN @Number % 100 IN (11, 12, 13) THEN 'th'
    ELSE 
        CASE @Number % 10
            WHEN 1 THEN 'st'
            WHEN 2 THEN 'nd'
            WHEN 3 THEN 'rd'
        ELSE 'th'
        END
    END 

答案 5 :(得分:1)

这对于任何数字

都会好得多
 create Function dbo.fn_Numbers_Ordinal (@N as bigint) returns varchar(50) 
 as Begin
 Declare @a as varchar(50)= CAST(@N AS VARCHAR(50))
return(
SELECT  CAST(@N AS VARCHAR(50))
    +
    CASE
        WHEN Right(@a,2)='11' or Right(@a,2)='12' or Right(@a,2)='13'  Then 'th'
        WHEN @N % 10 = 1 THEN 'st'
        WHEN @N % 10 = 2 THEN 'nd'
        WHEN @N % 10 = 3 THEN 'rd'
        ELSE 'th' --for @N % 10 IN (4,5,6,7,8,9,0)
    END

)
end

答案 6 :(得分:0)

Public Function OrdinalNumberSuffix(ByVal InNumber As Integer) As String
Dim StrNumber As String, _
    Digit     As Byte, _
    Suffix    As String

    StrNumber = Trim(Str(InNumber))
    If Val(StrNumber) > 3 And Val(StrNumber) < 14 Then
        Digit = Val(Right(StrNumber, 2))
    Else
        Digit = Val(Right(StrNumber, 1))
    End If
    Select Case Digit
        Case 1:    Suffix = "st"
        Case 2:    Suffix = "nd"
        Case 3:    Suffix = "rd"
        Case Else: Suffix = "th"
    End Select
    OrdinalNumberSuffix = " " & StrNumber & Suffix & " "
End Function

答案 7 :(得分:0)

DECLARE @Number int = 113,         @Superscript int 如果@Number不是NULL BEGIN

ThreadPriority

结束     选择0作为数字,&#39; th&#39;作为上标

答案 8 :(得分:0)

我想我会添加各种选项。这是一线。大约一年前,我将此留为评论。但是有人建议我把它作为答案。所以,你去:

SELECT OrdinalRank = CONCAT(num, IIF(num % 100 IN (11,12,13),'th',COALESCE(CHOOSE(num % 10,'st','nd','rd'),'th')))
FROM (
    VALUES (1),(2),(3),(4),(5),(10),(11),(20),(21),(22),(23),(24),(101),(102),(103)
) x(num)

--Result:
--1st
--2nd
--3rd
--4th
--5th
--10th
--11th
--20th
--21st
--22nd
--23rd
--24th
--101st
--102nd
--103rd

这利用了IIFCHOOSE函数,它们仅在SQL 2012+中可用。

答案 9 :(得分:-1)

使用下面的SSRS表达式:

= DAY(Globals!ExecutionTime) & 
    SWITCH(
    DAY(Globals!ExecutionTime)= 1 OR DAY(Globals!ExecutionTime) = 21 OR DAY(Globals!ExecutionTime)=31, "st",
    DAY(Globals!ExecutionTime)= 2 OR DAY(Globals!ExecutionTime) = 22 , "nd",
    DAY(Globals!ExecutionTime)= 3 OR DAY(Globals!ExecutionTime) = 23 , "rd",
    true, "th"
    )

这很容易实现并且效果很好。