【问题标题】:Convert YYYYMM string to date YYYY-MM-DD with day 1将 YYYYMM 字符串转换为第 1 天的日期 YYYY-MM-DD
【发布时间】:2019-04-16 09:30:45
【问题描述】:

我在表格中有这一列 Startmonth,日期如下:YYYYMM,所以 201801201707强>等

我希望在我的视图中创建此列,但转换为日期,例如 YYYY-MM-DD,将日期作为本月的第一天,所以 **201801 > 2018-01-01 和 201707 > 2017-07-01。 **

我不断收到错误:

从字符转换日期和/或时间时转换失败 字符串。

谁能帮帮我?

我试过这个:

select convert (DATE, concat (s.StartMonth,'01'), 102) as SubscriptionStart

from incident i

left join imcustomerid cid on i.accountid = cid.accountid
left join billing_subscription s on cid.imcustomerid = s.idcustomer
left join billing_subscriptiontype st on s.idsubscriptiontype = st.id

【问题讨论】:

  • 你确定这是MySql吗?
  • 当使用硬编码字符串而不是列(即“201811”)时,您的代码对我来说都很好,102112 作为类型。 StartMonth 是什么类型的?它可以包含空格吗?
  • 注意,date 数据类型没有格式;日期(时间)数据类型存储为二进制表示。您的表示层选择显示日期的格式(例如,SSMS 对于大多数用户默认使用yyyy-MM-dd)。
  • @JoakimDanielson 不,没有空格。当我尝试使用 'from billing_subscription s' 转换它时(所以没有连接)它工作得很好,所以我不太明白为什么添加一些连接时它不起作用。
  • SELECT StartMonth FROM billing_subscription WHERE TRY_CONVERT(date, concat (StartMonth,'01')) IS NULL AND StartMonth IS NOT NULL; 添加结果。我怀疑您的数据并非全部采用yyyyMM 格式。

标签: sql sql-server


【解决方案1】:

尝试使用

select convert (DATE, concat (s.StartMonth,'01'), 112) as SubscriptionStart

select cast(concat (s.StartMonth,'01') as date) as SubscriptionStart

CAST and CONVERT (Transact-SQL)

我认为最好在这里使用TRY_CONVERT,正如@Larnu所说:

select try_convert(date, s.StartMonth+'01', 112) as SubscriptionStart

+ 而不是CONCAT 以正确转换NULL 值。

【讨论】:

  • 仍然得到完全相同的错误。它们在没有连接语句的情况下工作,但在连接时不能工作。
  • 尝试使用ISDATE - SELECT ISDATE('20120101'),ISDATE('20121301')检查StartMonth + 01
  • 代码应该在没有样式参数的情况下工作。你只是有坏数据......201913foobar
  • @user11299833 - SELECT s.* FROM billing_subscription s WHERE ISDATE(CONCAT(s.StartMonth,'01'))=0
  • 不喜欢ISDATE,@SergeyMenshov。例如 SELECT ISDATE(2017); 返回 1,但 SELECT CONVERT(date, 2017); 将失败。 TRY_CONVERT 是一个更好的工具。
【解决方案2】:

问题是您正在使用字符串对表进行左连接,这意味着如果incident 行没有匹配的行,则它有时可能为空,然后转换失败

这是解决这个问题的一种方法

SELECT CASE WHEN s.StartMonth IS NOT NULL THEN convert(DATE, concat (s.StartMonth,'01'), 112)
       ELSE null -- Or return some default value, otherwise this row can be removed
       END  as SubscriptionStart
FROM incident i
LEFT JOIN imcustomerid cid ON i.accountid = cid.accountid
LEFT JOIN billing_subscription s ON cid.imcustomerid = s.idcustomer
LEFT JOIN billing_subscriptiontype st ON s.idsubscriptiontype = st.id

另一种方法是使用 TRY_CONVERT 而不是另一个答案中提到的 CASE,这取决于您在 null 时要返回的内容。

【讨论】:

  • CONVERT(date,NULL) 返回NULL。这不会解决问题。 TRY_CONVERT 将阻止 SQL 提供错误,但可能无法为 OP 提供所需的结果。
  • @Larnu 我在哪里可以转换空值?
  • 为了更短,你可以在这里跳过ELSE null
  • @SergeyMenshov 我知道,但我认为你可以有一个默认结果会更清楚。我也许应该添加评论。
  • “意味着如果事件行没有匹配的行然后转换失败,则它有时可能为空”。你是说CONVERT 会产生一个错误,如果要转换的值是NULL;那不是真的。该查询仍会产生 OP 得到的错误,因为 CASE 是多余的。整个 CASE 可以写成 convert(DATE, concat (s.StartMonth,'01'), 112) 并且结果完全相同(因此会出错,因为 OP 的值显然不是 yyyyMM 格式的值)。
【解决方案3】:

我认为最清晰的方法是datefromparts()

select datefromparts(year(s.StartMonth),
                     month(s.StartMonth),
                     1) as SubscriptionStart

更传统的方法是减去天数:

select dateadd(day,
               (1 - day(s.StartMonth)),
               s.StartMonth
              ) as SubscriptionStart

我确实建议为此将日期转换为字符串。绝对没有必要,而且日期与字符串不同。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-09-03
    • 2018-05-19
    • 2011-11-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-09
    • 2018-03-27
    相关资源
    最近更新 更多