【问题标题】:CONVERT Date INT to DATE in SQL在 SQL 中将日期 INT 转换为日期
【发布时间】:2020-10-03 15:06:22
【问题描述】:

如何将日期整数转换为日期类型? (20200531 到 2020 年 5 月 31 日)

我当前的表格有一个格式为 YYYYMMDD(20200531、20200430 等)的数据日期

根据我正在使用的 Toad Data Point 软件,datadate 的数据类型是 int。我相信它使用的是 ORACLE sql 数据库。

因此,在查询这些数据时,我必须输入 where 子句,如下所示..

where datadate = '20200531'

我的目标是将此整数数据日期转换为日期格式 (5/31/2020),以便我可以将数据日期应用于 where 子句。

喜欢..

WHERE datadate = dateadd(DD, -1, CAST(getdate() as date))

【问题讨论】:

  • 指定哪个sql?
  • 当您说“数据集”时,您是指 SQL 表吗?告诉我们datadate 类型。
  • “日期整数”不是你想象的那样。你在string 中有一个格式化的日期。实际的整数日期将是 UNIX 时间戳值。
  • 请确认datadate 列的确切数据类型(不是“日期类型”)。真的是char/varchar/nchar/nvarchar专栏吗?
  • 两个观察结果:首先,您的陈述“我相信它使用的是 ORACLE sql 数据库。” (强调我的)。您必须知道您正在处理的数据库是什么,因为任何和所有可能的解决方案都取决于此。其次,同样必须知道该列是什么数据类型。如果它是除 DATE 之外的任何东西(在 oracle 中,或在其他数据库中的等效项),那么您就有一个非常严重的设计缺陷。

标签: sql oracle date where-clause


【解决方案1】:

(如果它是int 列,请阅读下面的答案)

假设它是一个文本字符串:

假设datadate 是一个字符串(字符、文本等)列而不是date/datetime/datetime2/datetimeoffset 列,则将CONVERT 函数与style: 23 一起使用. 23 值对应于 ISO 8601,因为这些值按 yyyy-MM-dd 顺序排列,即使它们缺少破折号。

此页面有style编号的引用:https://docs.microsoft.com/en-us/sql/t-sql/functions/cast-and-convert-transact-sql?view=sql-server-ver15

SELECT
    *
FROM
    (
        SELECT
            myTable.*
            CONVERT( date, datadate, 23 ) AS valueAsDate
        FROM
            myTable
    ) AS q
WHERE
    q.valueAsDate = DATEADD( dd, -1, GETDATE() )

假设它是一个实际的int 列:

快速而简单的方法是将int 转换为varchar,然后使用与上面相同的代码,就好像它是一个文本字段一样 - 但不要这样做因为它很慢:

SELECT
    *
FROM
    (
        SELECT
            myTable.*,
            CONVERT( char(8), datadate ) AS valueAsChar,
            CONVERT( date, CONVERT( char(8), datadate ), 23 ) AS valueAsDate
        FROM
            myTable
    ) AS q
WHERE
    q.valueAsDate = DATEADD( dd, -1, GETDATE() )

假设它是一个实际的 int 列(更好的答案):

我们需要使用 DATEFROMPARTS 并使用 Base-10 算法提取每个组件 (fun)!

如果我们有一个表示格式化日期的整数(恐怖),例如20200531,那么:

  • 我们可以通过执行MOD 31(例如19950707 MOD 31 == 7)来获得这一天
  • 我们可以先除以100去掉日部分,然后MOD 12:(例如20200531 / 100 == 202005202005 MOD 12 == 5)得到月份
  • 我们可以通过除以10,000 得到年份(例如20200531 / 10000 == 2020)。

顺便说一句:

  • SQL Server 使用 % 代替 MOD 作为模运算符。
  • 整数除法会导致截断,而不是产生十进制或浮点值(例如 5 / 2 == 2 而不是 2.5)。

像这样:

SELECT
    q2.* 
FROM
    (
        SELECT
            q.*,
            DATEFROMPARTS( q.[Year], q.MonthOfYear, q.DayOfMonth ) AS valueAsDate
        FROM
            (
                SELECT
                    myTable.*,

                    ( datadate % 31 ) AS DayOfMonth,
                    ( ( datadate / 100 ) % 12 ) AS MonthOfYear,
                   ( datadate / 10000 ) AS [Year]
                FROM
                    myTable
            ) AS q
    ) AS q2
WHERE
    q2.valueAsDate = DATEADD( dd, -1, GETDATE() )

显然,使用两个嵌套子查询是一件很痛苦的事情 (SQL 的人机工程学很糟糕,我不明白 SQL 如何或为什么不允许 SELECT 子句中的表达式被其他表达式使用在同一个查询中 - 人体工程学真的很糟糕......) - 但我们可以将其转换为标量 UDF(和SQL Server will inline scalar UDFs,因此不会影响性能)。

此函数中有一个 TRY/CATCH 块,因为您可能会处理像 20209900 这样的无效值(这不是真实日期,因为 2020 年没有第 99 个月和第 0 天) .在这种情况下,函数返回NULL

CREATE FUNCTION dbo.convertHorribleIntegerDate( @value int ) RETURNS date AS
BEGIN

    DECLARE @dayOfMonth  int = @value % 31;
    DECLARE @monthOfYear int = ( @value / 100 ) % 100;
    DECLARE @year        int = @value / 10000;

    BEGIN TRY
        RETURN DATEFROMPARTS( @dayOfMonth, @monthOfYear, @year );    
    END TRY;
    BEGIN CATCH
        RETURN NULL;
    END CATCH;

END

我们可以在这样的查询中使用:

SELECT
    myTable.*,
    dbo.convertHorribleIntegerDate( datadate ) AS valueAsDate
FROM
    myTable

由于SELECT 无法与同一查询中的其他表达式共享表达式结果,您仍然需要使用外部查询来处理valueAsDate(或重复dbo.convertHorribleIntegerDate 函数调用):

SELECT
    *
FROM
    (
        SELECT
            myTable.*,
            dbo.convertHorribleIntegerDate( datadate ) AS valueAsDate
        FROM
            myTable
    ) AS q
WHERE
    q.valueAsDate = DATEADD( dd, -1, GETDATE() )

【讨论】:

    【解决方案2】:

    此答案假定您正在运行 Oracle,如您的问题中所建议的那样。

    如何将日期整数转换为日期类型? (20200531 到 2020 年 5 月 31 日)

    在 Oracle 中,您使用 to_date() 将字符串转换为数字。如果您给它一个数字,它会在转换之前将其隐式转换为字符串。所以在这两种情况下,你都会这样做:

    to_date(datadate, 'yyyymmdd')
    

    我的目标是将此整数数据日期转换为日期格式 (5/31/2020),以便我可以将数据日期应用于 where 子句。

    一般情况下,您希望避免在where 谓词中的列上应用函数:它效率不高,因为数据库需要在整个列上应用函数之前过滤。如果您想从昨天开始过滤 dateadd,那么我建议您计算昨天的日期并将其以与过滤列相同的格式放置,这样您就可以直接匹配现有的列值。

    如果您的列是字符串:

    where datadatea = to_char(sysdate - 1, 'yyyymmdd')
    

    如果是数字:

    where datadatea = to_number(to_char(sysdate - 1, 'yyyymmdd'))
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-05-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-03-07
      相关资源
      最近更新 更多