1

我的表中有一个 INT 列。此列以特殊格式存储日期。我正在尝试将该列转换为 DATE 类型。

例如,我们保持'2016-03-14'20160314

例外情况是,对于每个月的最后一天,我们不存储日期。因此,对于'2016-03-31'我们存储201603,我必须考虑是否less than 999999要查找数字是代表月末还是月中的其他日子。

到目前为止,我有 2 个查询来完成此任务:

查询一:

这都是数学公式。

declare @k int = 20160321
--declare @k int = 201603
select 
    IIF(@k < 999999
        , EOMONTH(DATEFROMPARTS(@k /100, @k % 100, 1), 0)
        , DATEFROMPARTS(@k /10000, (@k / 100) % 100, @k % 100)
    )

查询 2: 这个是使用字符串操作。

declare @k int = 20160321
--declare @k int = 201603

select 
    IIF(@k < 999999
        , EOMONTH(cast(LEFT(@k, 4) + '-' + RIGHT(@k, 2) + '-01'  as date), 0)
        , cast(LEFT(@k, 4) + '-' + RIGHT(LEFT(@k, 6), 2) + '-' + RIGHT(@k, 2) as date )
    ) AS DateColumn

我需要在WHERE子句中做转换公式。就像是:

SELECT K, Dt, Name -- and more fields
FROM tbl
WHERE IIF(K < 999999
            , EOMONTH(DATEFROMPARTS(K /100, K % 100, 1), 0)
            , DATEFROMPARTS(K /10000, (K / 100) % 100, K % 100)
        ) < GetDate()

performance is important

问题:有没有更好的方法来做到这一点?可能是 SQL Server 可以使用我在 K 列上的聚集索引的一种方式。

4

1 回答 1

1

我希望查询 1 的性能会更好,但您必须对其进行测试才能确定。我不知道什么样的表现datefromparts()datetimefromparts()有。它们相对较新,所以如果它们无缘无故地神奇地可怕,我不会感到震惊。您正在比较字符串操作和类型转换的性能与算术和类型转换的性能。我的猜测是它主要是一个洗涤,但算术可能更快。

在性能方面让我印象深刻的选项是:a)在您的表中添加一个日期时间列。b) 向表中添加计算列。如果你创建一个 PERSISTED 列,你甚至可以在它上面创建一个索引。c) 创建一个视图(如果您可以跳过需求环节,则为索引视图)。d) 使用日期时间字段创建一个新表并更新它。

(a) 和 (d) 都重复数据,因此它们并不像最初出现的那样出色。

我总是发现计算列有点粗糙,但它们工作得很好。如果您创建一个视图,则必须将其 INNER JOIN 才能使用它,但在大多数系统中,JOINS 非常快。

我可能会考虑创建一个持久的计算列或视图。当然,最好的解决方案是首先不要将日期存储为整数。


你可以试试这个查询:

SELECT CASE 
        WHEN @K < 999999 THEN EOMONTH(TRY_CONVERT(date, CAST(@K * 100 + 1 AS VARCHAR(10))))
        ELSE TRY_CONVERT(date, CAST(@K AS VARCHAR(10)))
    END AS K_Date

这可能起作用的原因是这YYYYMMDD是 ISO 日期格式之一。我以前会尝试TRY_CONVERT()过,CONVERT()因为查询引擎可以决定评估所有CONVERT而不查看CASE条件并抛出错误。

于 2016-04-27T21:26:54.377 回答