在SQL Server中按月份名自定义排序

时间:2016-11-22 18:40:59

标签: sql sql-server sorting sql-server-2012

我有一张表,其中某些日期放置了一定数量的条目。这是表结构:

Traceback (most recent call last):
  File "C:/Users/SHUBHAM/Desktop/Python1.py", line 1, in <module>
    x= input('What is your name? ')
  File "<string>", line 1, in <module>
NameError: name 'shubham' is not defined

ID EntryName Entries DateOfEntry 1 A 20 2016-01-17 2 B 22 2016-01-29 3 C 23 2016-02-17 4 D 19 2016-02-17 5 E 29 2016-03-17 6 F 30 2016-03-17 7 G 43 2016-04-17 8 H 10 2016-04-17 9 I 5 2016-05-17 10 J 120 2016-05-17 11 K 220 2016-06-17 12 L 210 2016-06-17 13 M 10 2016-07-17 14 N 20 2016-07-17 15 O 15 2016-08-17 16 P 17 2016-08-17 17 Q 19 2016-09-17 18 R 23 2016-09-17 19 S 43 2016-10-17 20 T 56 2016-10-17 21 U 65 2016-11-17 22 V 78 2016-11-17 23 W 12 2016-12-17 24 X 23 2016-12-17 25 Y 43 2016-02-17 26 Z 67 2016-03-17 27 AA 35 2015-01-17 28 AB 23 2015-01-29 29 AC 43 2015-02-17 30 AD 35 2015-02-17 31 AE 45 2015-03-17 32 AF 23 2015-03-17 33 AG 43 2015-04-17 34 AH 19 2015-04-17 35 AI 21 2015-05-17 36 AJ 13 2015-05-17 37 AK 22 2015-06-17 38 AL 45 2015-06-17 39 AM 66 2015-07-17 40 AN 77 2015-07-17 41 AO 89 2015-08-17 42 AP 127 2015-08-17 43 AQ 19 2015-09-17 44 AR 223 2015-09-17 45 AS 143 2015-10-17 46 AT 36 2015-10-17 47 AU 45 2015-11-17 48 AV 28 2015-11-17 49 AW 72 2015-12-17 50 AX 24 2015-12-17 51 AY 46 2015-02-17 52 AZ 62 2015-03-17 是条目标识符,列EntryName具有Entries列中指定日期的条目总数。

我正在尝试制定一个查询,其中以月为单位显示条目总数。我目前有这个问题:

DateOfEntry

只要显示结果就可以正常工作。但是,我的问题是我需要按月对结果进行排序,其中起始月份是动态的,即来自参数(由用户提供)。

这意味着,如果用户选择2015年5月,则应从2015年5月到2016年4月对结果进行排序。同样,如果用户选择2015年10月,则结果将显示在2015年10月至2016年9月。< /强>

我如何在SELECT DateName(MONTH, e.DateOfEntry) AS MonthOfEntry, MONTH(e.DateOfEntry) AS MonthNumber, SUM(e.Entries) AS TotalEntries FROM #entry e GROUP BY MONTH(e.DateOfEntry), DateName(MONTH,e.DateOfEntry) ORDER BY MONTH(e.DateOfEntry) ASC 条款中获得此条件?

6 个答案:

答案 0 :(得分:2)

您可以使用模运算将偏移量放入ORDER BY。四月:

ORDER BY (MONTH(e.DateOfEntry) + 12 - 4) % 12
--------------------------------------^ month number to start with

+ 12就是这样,我不必记住%是否返回带有负操作数的负数。)

如果您想按时间顺序排列结果,可以改为:

ORDER BY MIN(e.DateOfEntry)

答案 1 :(得分:1)

如果我理解正确

“这意味着如果用户选择2015年5月,结果应该从2015年5月到2016年4月排序。同样,如果用户选择2015年10月,结果将显示从2015年10月到2016年9月。”

这应该有效:

示例数据:

IF OBJECT_ID('tempdb..#entry') IS NOT NULL
    DROP TABLE #entry;

CREATE TABLE #entry(ID INT ,EntryName  VARCHAR(10)  , Entries  INT ,  DateOfEntry DATE);

INSERT INTO #entry (ID  ,EntryName     ,Entries   ,DateOfEntry)
VALUES
(1 ,'A', 20     ,'2016-01-17'),
(2 ,'B', 22     ,'2016-01-29'),
(3 ,'C', 23     ,'2016-02-17'),
(4 ,'D', 19     ,'2016-02-17'),
(5 ,'E', 29     ,'2016-03-17'),
(6 ,'F', 30     ,'2016-03-17'),
(7 ,'G', 43     ,'2016-04-17'),
(8 ,'H', 10     ,'2016-04-17'),
(9 ,'I', 5      ,'2016-05-17'),
(10,'J', 120    ,'2016-05-17'),
(11,'K', 220    ,'2016-06-17'),
(12,'L', 210    ,'2016-06-17'),
(13,'M', 10     ,'2016-07-17'),
(14,'N', 20     ,'2016-07-17'),
(15,'O', 15     ,'2016-08-17'),
(16,'P', 17     ,'2016-08-17'),
(17,'Q', 19     ,'2016-09-17'),
(18,'R', 23     ,'2016-09-17'),
(19,'S', 43     ,'2016-10-17'),
(20,'T', 56     ,'2016-10-17'),
(21,'U', 65     ,'2016-11-17'),
(22,'V', 78     ,'2016-11-17'),
(23,'W', 12     ,'2016-12-17'),
(24,'X', 23     ,'2016-12-17'),
(25,'Y', 43     ,'2016-02-17'),
(26,'Z', 67     ,'2016-03-17'),
(27,'AA',35     ,'2015-01-17'),
(28,'AB',23     ,'2015-01-29'),
(29,'AC',43     ,'2015-02-17'),
(30,'AD',35     ,'2015-02-17'),
(31,'AE',45     ,'2015-03-17'),
(32,'AF',23     ,'2015-03-17'),
(33,'AG',43     ,'2015-04-17'),
(34,'AH',19     ,'2015-04-17'),
(35,'AI',21     ,'2015-05-17'),
(36,'AJ',13     ,'2015-05-17'),
(37,'AK',22     ,'2015-06-17'),
(38,'AL',45     ,'2015-06-17'),
(39,'AM',66     ,'2015-07-17'),
(40,'AN',77     ,'2015-07-17'),
(41,'AO',89     ,'2015-08-17'),
(42,'AP',127    ,'2015-08-17'),
(43,'AQ',19     ,'2015-09-17'),
(44,'AR',223    ,'2015-09-17'),
(45,'AS',143    ,'2015-10-17'),
(46,'AT',36     ,'2015-10-17'),
(47,'AU',45     ,'2015-11-17'),
(48,'AV',28     ,'2015-11-17'),
(49,'AW',72     ,'2015-12-17'),
(50,'AX',24     ,'2015-12-17'),
(51,'AY',46     ,'2015-02-17'),
(52,'AZ',62     ,'2015-03-17')

查询参数:

DECLARE @Month VARCHAR(2) = '05', @Year VARCHAR(4) = '2015'

SELECT      DateName(MONTH, e.DateOfEntry) AS MonthOfEntry,
            MONTH(e.DateOfEntry) AS MonthNumber,
            SUM(e.Entries) AS TotalEntries
FROM        #entry e
WHERE CAST(e.DateOfEntry AS DATE) >= CAST( @Year+@Month+'01' AS DATE)
GROUP BY    MONTH(e.DateOfEntry), DateName(MONTH,e.DateOfEntry)
ORDER BY    MONTH(e.DateOfEntry) ASC

结果:

enter image description here

答案 2 :(得分:1)

您可以按顺序使用belosw

  ORDER BY YEAR(e.DATEOFENTRY),    
  DATEPART(MM,e.DAREOFENTRY)

这将首先对年份和下一个月的结果进行排序。

您需要在Select中指定这些相同的列。

答案 3 :(得分:0)

假设您的参数是一个名为@FirstMonth的整数,您可以使用以下方式获得正确的月份订单:

案例

  WHEN MONTH(e.DateOfEntry) < @FirstMonth then MONTH(e.DateOfEntry) + 12

   ELSE MONTH(e.DateOfEntry)

END AS MonthNumber

答案 4 :(得分:0)

在我遇到的所有答案和建议中,我发现这种方式(xQbert在问题&#39; s评论中建议的)是最简单的

SELECT      DateName(MONTH, e.DateOfEntry) + ' ' + CONVERT(NVARCHAR(100), YEAR(e.DateOfEntry)) AS MonthOfEntry,
            MONTH(e.DateOfEntry) AS MonthNumber,
            SUM(e.Entries) AS TotalEntries
FROM        Entry e
WHERE       e.DateOfEntry BETWEEN @StartDate AND (DATEADD(YEAR, 1, @StartDate))
GROUP BY    MONTH(e.DateOfEntry), DateName(MONTH,e.DateOfEntry), YEAR(e.DateOfEntry)
ORDER BY    YEAR(e.DateOfEntry) ASC, MONTH(e.DateOfEntry) ASC

要证明这一点:http://rextester.com/CJFFP5640

最初,我使用以下查询:

SELECT      sortingList.MonthOfEntry,
            sortingList.TotalEntries,
            sortingList.MonthNumber
FROM        (
              SELECT            DateName(MONTH, DATEADD(MONTH, MONTH(e.DateOfEntry), 0) - 1) + ' ' + CONVERT(nvarchar(20),YEAR(e.DateOfEntry)) AS MonthOfEntry,
                                SUM(e.Entries) as TotalEntries,
                                CASE
                                    WHEN    ((MONTH(e.DateOfEntry) - MONTH(@StartDate)) > 0)
                                    THEN    (MONTH(e.DateOfEntry) - MONTH(@StartDate)) + 1
                                    WHEN    ((MONTH(e.DateOfEntry) - MONTH(@StartDate)) = 0)
                                    THEN    1
                                    ELSE 
                                            ((12 - MONTH(@StartDate)) + (MONTH(e.DateOfEntry))) + 1
                                END
                                AS MonthNumber
              FROM              Entry e
              WHERE             e.DateOfEntry >= @StartDate AND e.DateOfEntry < DATEADD(YEAR, 1, @StartDate)
              GROUP BY          DateName(MONTH, DATEADD(MONTH, MONTH(e.DateOfEntry), 0) - 1), YEAR(e.DateOfEntry), MONTH(e.DateOfEntry) - MONTH(@StartDate), MONTH(e.DateOfEntry)
            ) sortingList
ORDER BY    sortingList.MonthNumber ASC

这是一个小提琴来证明这一点:http://rextester.com/LEVD30653

说明(非TL; DR)

您可以看到它基本上是相同的WHERE子句。但是,顶部的查询使用更简单的逻辑进行排序,并且更流畅和可读。

请注意,第二个解决方案(使用CASE语句)根据用户提供的月份编号对月份数进行排序,即如果用户提供2015年12月,则第二个解决方案将2015年12月编号为1, 2016年1月为2016年2月2日为3,依此类推。在您希望处理此数据的情况下,这可能更有用。

就我的用例而言,这更有意义。但是,就问题的范围而言,顶部的查询是最好的。

答案 5 :(得分:0)

为查询添加where子句

WHERE MONTH(e.DateOfEntry) < User.Month AND YEAR(e.DateOfEntry) < User.Year AND  MONTH(e.DateOfEntry) > (User.Month-1) AND YEAR(e.DateOfEntry) > (User.Year+1)