我在按下面的查询顺序排序月份名称时遇到困难。实际上,此处Period
是别名,如果用户希望每天,每周,每月或每年查看结果,则可以选择该别名。排序适用于除月份以外的其他情况。由于它只将Month作为字符串,如果我尝试将其转换为月份,则会给出异常。
请看一看并指导我。
开始返回如:
April
August
December
期望的输出:
January
February
March
April
December
代码:
Declare @Period char = 'M'
Declare @FinalDateId int = 20170101;
SELECT
Period, SUM(CAST(TotalAmount AS bIGINT)) AS Value
FROM
(SELECT
CASE
WHEN @Period = 'D'
THEN CAST(d.DateName AS VARCHAR(50))
WHEN @Period = 'W'
THEN CAST(d.WeekOfYear AS VARCHAR(50))
WHEN @Period = 'M'
THEN CAST(d.MonthName AS VARCHAR(50))
WHEN @Period = 'Y'
THEN CAST(d.CalendarYear AS VARCHAR(50))
END AS Period,
Tr.TotalAmount
FROM
Revenue AS Tr
INNER JOIN
Dates AS d ON Tr.DateId = d.Id
WHERE
(Tr.DateId BETWEEN
CASE
WHEN @Period = 'D'
THEN CONVERT(varchar, CONVERT(datetime, CONVERT(char(8), @FinalDateId)) - 30, 112)
WHEN @Period = 'W'
THEN CONVERT(varchar, CONVERT(datetime, CONVERT(char(8), @FinalDateId)) - 364, 112)
WHEN @Period = 'M'
THEN CONVERT(varchar, CONVERT(datetime, CONVERT(char(8), @FinalDateId)) - 365, 112)
WHEN @Period = 'Y'
THEN CONVERT(varchar, CONVERT(datetime, CONVERT(char(8), @FinalDateId)) - 3652, 112) END AND @FinalDateId)
) AS TotalRevenue
GROUP BY
Period
ORDER BY
CASE
WHEN @Period = 'M'
THEN CONVERT(month, Period)
END
输出没有排序返回:
Period Value
--------------------
April 4750
August 4750
December 187250
February 4000
January 12500
对月份进行排序后的所需输出:
Period Value
-----------------------
January 12500
February 4000
April 4750
August 4750
December 187250
分享样本数据/表格
答案 0 :(得分:1)
无法理解代码的工作原理。 “CONVERT(month,Period)”无效(至少在我的sql server机器中它说“mont不是系统数据类型”)。
除此之外,我认为最好的解决方案是订购另一个字段:
CASE
WHEN @Period = 'D'
THEN DATEPART(DAY,d.id)
WHEN @Period = 'W'
THEN DATEPART(WEEK,d.id)
WHEN @Period = 'M'
THEN DATEPART(MONTH,d.id)
WHEN @Period = 'Y'
THEN DATEPART(YEAR,d.id)
END AS PeriodNumber
答案 1 :(得分:1)
不要乱用日期部分的名称!
使用月份名称和某个日期片段构建完整日期的任何方法都会失败,如果执行系统有不同的话,将会失败,以获取月份的号码语言。如果您的应用程序可能在国际环境中运行,那么您必须找到一种方法来处理它而不会出现问题。
如果期间是某个地方的实际日期,您可以简单地使用YEAR()
和MONTH()
来提取年份和月份,并按两者排序。两者都带有数字索引。
但解决方案似乎更简单:
显然你正在使用日期表(这是一件非常好的事情!)
从我发布的示例中我看到,其列[MonthOfYear]
已获得数字月份索引。你也得到了FiscalYear
。因此,请在查询中包含这些列,然后使用ORDER BY FiscalYear,MonthOfYear
。
答案 2 :(得分:1)
我把它作为第二个答案,因为这是一个笑话的一半:
查看此表_
select * from sys.syslanguages
您可以使用带编号的 string-split-approach 来获取给定月份名称的月份索引。这使您可以动态地处理不同的文化:
SELECT ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS MonthIndex
,B.m.value('text()[1]','nvarchar(max)') AS MonthName
FROM sys.syslanguages AS l
CROSS APPLY(SELECT CAST('<x>' + REPLACE(months,',','</x><x>') + '</x>' AS XML) AS Casted) AS A
CROSS APPLY A.Casted.nodes('/x') AS B(m)
WHERE l.name='us_english';
但我的强烈建议是:不要这样做:-D
Inx Name
------------
1 January
2 February
3 March
4 April
5 May
6 June
7 July
8 August
9 September
10 October
11 November
12 December
答案 3 :(得分:1)
在这里,我使用了@froxon和@Shnugo提供的评论。我非常感谢那些帮助我做出最终答案的人们。
Declare @Period char = 'M'
Declare @FinalDateId int = 20170101;
SELECT
Period, SUM(CAST(TotalAmount AS bIGINT)) AS Value
FROM
(SELECT
CASE
WHEN @Period = 'D'
THEN CAST(d.DateName AS VARCHAR(50))
WHEN @Period = 'W'
THEN CAST(d.WeekOfYear AS VARCHAR(50))
WHEN @Period = 'M'
THEN CAST(d.MonthName AS VARCHAR(50))
WHEN @Period = 'Y'
THEN CAST(d.CalendarYear AS VARCHAR(50))
END AS Period,
Tr.TotalAmount,
d.CalendarYear,
CASE
WHEN @Period = 'D'
THEN DATEPART(DAY,d.DateName)
WHEN @Period = 'W'
THEN DATEPART(WEEK,d.DateName)
WHEN @Period = 'M'
THEN DATEPART(MONTH,d.DateName)
WHEN @Period = 'Y'
THEN DATEPART(YEAR,d.DateName)
END AS PeriodNumber
FROM
Revenue AS Tr
INNER JOIN
Dates AS d ON Tr.DateId = d.Id
WHERE
(Tr.DateId BETWEEN
CASE
WHEN @Period = 'D'
THEN CONVERT(varchar, CONVERT(datetime, CONVERT(char(8), @FinalDateId)) - 30, 112)
WHEN @Period = 'W'
THEN CONVERT(varchar, CONVERT(datetime, CONVERT(char(8), @FinalDateId)) - 364, 112)
WHEN @Period = 'M'
THEN CONVERT(varchar, CONVERT(datetime, CONVERT(char(8), @FinalDateId)) - 365, 112)
WHEN @Period = 'Y'
THEN CONVERT(varchar, CONVERT(datetime, CONVERT(char(8), @FinalDateId)) - 3652, 112) END AND @FinalDateId)
) AS TotalRevenue
GROUP BY
Period,
PeriodNumber,
CalendarYear
Order by
CalendarYear,
PeriodNumber
答案 4 :(得分:0)
基本思路是将月份名称转换为月份,并相应地进行排序。 我试过一种方法,如果它有效,有多种转换检查方法。
Declare @Period char = 'M'
Declare @FinalDateId int = 20170101;
SELECT
Period, SUM(CAST(TotalAmount AS bIGINT)) AS Value
FROM
(SELECT
CASE
WHEN @Period = 'D'
THEN CAST(d.DateName AS VARCHAR(50))
WHEN @Period = 'W'
THEN CAST(d.WeekOfYear AS VARCHAR(50))
WHEN @Period = 'M'
THEN CAST(d.MonthName AS VARCHAR(50))
WHEN @Period = 'Y'
THEN CAST(d.CalendarYear AS VARCHAR(50))
END AS Period,
Tr.TotalAmount
FROM
Revenue AS Tr
INNER JOIN
Dates AS d ON Tr.DateId = d.Id
WHERE
(Tr.DateId BETWEEN
CASE
WHEN @Period = 'D'
THEN CONVERT(varchar, CONVERT(datetime, CONVERT(char(8), @FinalDateId)) - 30, 112)
WHEN @Period = 'W'
THEN CONVERT(varchar, CONVERT(datetime, CONVERT(char(8), @FinalDateId)) - 364, 112)
WHEN @Period = 'M'
THEN CONVERT(varchar, CONVERT(datetime, CONVERT(char(8), @FinalDateId)) - 365, 112)
WHEN @Period = 'Y'
THEN CONVERT(varchar, CONVERT(datetime, CONVERT(char(8), @FinalDateId)) - 3652, 112) END AND @FinalDateId)
) AS TotalRevenue
GROUP BY
Period
ORDER BY
CASE
WHEN @Period = 'M'
THEN DATEPART(MM,convert(datetime,Period +'01 2017',110))
END
output:-
Period Value
January 12500
February 4000
March 2300
April 4750
May 8560
June 4400
July 4550
August 4750
September 5960
October 7350
November 5250
December 187250