【问题标题】:SQL order by Date from concatenated Month and Year stringSQL order by Date 从连接的月份和年份字符串
【发布时间】:2017-09-05 22:52:01
【问题描述】:

我有一个有趣的查询,其中的聚合排序不正确,因为它以字母数字顺序排列日期,因为它们是字符串 (VARCHARS)。如下。

DROP PROCEDURE dbo.DeploymentReport
GO

CREATE PROCEDURE dbo.DeploymentReport
@Date DATE
AS
BEGIN
SELECT TOP 6 DATENAME(MONTH,DeployDate) + ' - '  + DATENAME(YEAR,DeployDate) AS 'Month', 
       ISNULL(SUM(CASE WHEN OverallRiskRating = 3 THEN 1 END),0) AS 'High',
       ISNULL(SUM(CASE WHEN OverallRiskRating = 2 THEN 1 END),0) AS 'Med',
       ISNULL(SUM(CASE WHEN OverallRiskRating = 1 THEN 1 END),0) AS 'Low'      
FROM dbo.ChangeEvaluationForm cef
INNER JOIN dbo.Package pac
ON cef.ChangeId = pac.ChangeId
INNER JOIN dbo.SDMTicket sdm
ON pac.PackageId = sdm.PackageId
WHERE DeployDate < @Date
GROUP BY DATENAME(MONTH, DeployDate) + ' - '  + DATENAME(YEAR,DeployDate)
ORDER BY DATENAME(MONTH, DeployDate) + ' - '  + DATENAME(YEAR,DeployDate) DESC
END
GO

DECLARE @DateSelected DATETIME
SET @DateSelected = CONVERT(DATE,'2017-12-30')
EXECUTE dbo.DeploymentReport @Date = @DateSelected;

结果如下所示

如您所见,月份是按字母数字排序的,而不是按 DATE 排序的。

现在我对聚合查询绝对是残酷的,所以我的努力​​是改变 ORDER BY 行,以便它以某种方式解析“月份”列中的年和月,然后按年和月解析订单,而不改变结构数据返回。

这完全可能吗,或者我认为的方法是不可能的,或者是错误的思考方式?

【问题讨论】:

  • 只是不要按 DATENAME 订购。只需使用“ORDER BY DATEPART(mm,DeployDate) 等等

标签: sql sql-server


【解决方案1】:

您可以将year(DeployDate)month(DepolyDate) 添加到您的group by 子句中,因为您已经在group by 子句中使用了datename(year, DeployDate)datename(month, DeployDate),它应该没有任何效果,除了它将允许您在 order by 子句中使用它们:

CREATE PROCEDURE dbo.DeploymentReport
@Date DATE
AS
BEGIN
SELECT TOP 6 DATENAME(MONTH,DeployDate) + ' - '  + DATENAME(YEAR,DeployDate) AS 'Month', 
       ISNULL(SUM(CASE WHEN OverallRiskRating = 3 THEN 1 END),0) AS 'High',
       ISNULL(SUM(CASE WHEN OverallRiskRating = 2 THEN 1 END),0) AS 'Med',
       ISNULL(SUM(CASE WHEN OverallRiskRating = 1 THEN 1 END),0) AS 'Low'      
FROM dbo.ChangeEvaluationForm cef
INNER JOIN dbo.Package pac
ON cef.ChangeId = pac.ChangeId
INNER JOIN dbo.SDMTicket sdm
ON pac.PackageId = sdm.PackageId
WHERE DeployDate < @Date
GROUP BY DATENAME(MONTH, DeployDate) + ' - '  + DATENAME(YEAR,DeployDate), Year(DeployDate), Month(DeployDate)
ORDER BY Year(DeployDate) DESC, Month(DeployDate) DESC
END
GO

【讨论】:

  • 这也很有效,我实际上选择使用这个解决方案来代替可读性。
  • 很高兴为您提供帮助 :-)
【解决方案2】:

GROUP BY 逻辑转换为使用更“类似日期”分组列的子查询,然后在外部查询中应用TOPORDER BY

SELECT TOP 6 DATENAME(MONTH,DeployDate) + ' - '  + DATENAME(YEAR,DeployDate) AS 'Month',
      High,Med,Low
FROM (
       SELECT DATEADD(month,DATEDIFF(month,0,DeployDate),0) as DeployDate,
       ISNULL(SUM(CASE WHEN OverallRiskRating = 3 THEN 1 END),0) AS 'High',
       ISNULL(SUM(CASE WHEN OverallRiskRating = 2 THEN 1 END),0) AS 'Med',
       ISNULL(SUM(CASE WHEN OverallRiskRating = 1 THEN 1 END),0) AS 'Low'      
FROM dbo.ChangeEvaluationForm cef
INNER JOIN dbo.Package pac
ON cef.ChangeId = pac.ChangeId
INNER JOIN dbo.SDMTicket sdm
ON pac.PackageId = sdm.PackageId
WHERE DeployDate < @Date
GROUP BY DATEADD(month,DATEDIFF(month,0,DeployDate),0)
) t
ORDER BY DeployDate DESC

在这里,DATEADD(month,DATEDIFF(month,0,DeployDate),0)DeployDate 列向下舍入到相关月份的第一天的午夜 - 所以同一个月内的所有 DeployDate 值都会生成相同的值。对此列进行分组就相当于对字符串进行分组,但它仍然是datetime,因此可以在外部ORDER BY 中正确使用。 (并且仍然可以用来提取外部SELECT中的月份和年份分量)

【讨论】:

    【解决方案3】:

    您的时间跨度是有序的,所以我会在每个时间跨度中选择一个任意值并执行以下操作:

    ORDER BY MIN(DeployDate) DESC
    

    请注意,我更喜欢 YYYY-MM 格式;一个重要的原因是它可以正确订购。

    【讨论】:

      猜你喜欢
      • 2010-12-19
      • 2021-01-30
      • 2020-07-07
      • 2022-12-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-02-17
      • 2013-10-15
      相关资源
      最近更新 更多