将 varchar 值“Collect_Date”转换为数据类型 int 时转换失败

Posted

技术标签:

【中文标题】将 varchar 值“Collect_Date”转换为数据类型 int 时转换失败【英文标题】:Conversion failed when converting the varchar value 'Collect_Date' to data type int 【发布时间】:2019-03-13 22:25:48 【问题描述】:

我正在努力尝试将日期过滤器应用于我的查询。我不断收到此错误消息

将 varchar 值“Collect_Date”转换为 数据类型 int

这是我的代码:

SELECT
    Location_ID, 
    CONVERT(Date,CONVERT(varchar(10),Collect_Month_Key,101)) as 'Collect_Date', 
    Calc_Gross_Totals, Loc_Country, 
    CONVERT(varchar(8),Collect_Month_Key)+'-'+Location_ID as 'Unique Key'
FROM 
    FT_GPM_NPM_CYCLES, 
    LU_Location, 
    LU_Loc_Country
WHERE
    LU_Location.LU_Loc_Country_Key=LU_Loc_Country.LU_Loc_Country_Key
    AND FT_GPM_NPM_CYCLES.Lu_Loc_Key= LU_Location.LU_Loc_Key
    AND Collect_Month_Key<>-1 
    AND 'Collect_Date'>=2016-1-1
ORDER BY
    Location_ID, 
    Collect_Date;

如果有人可以提供帮助,我们将不胜感激。当我尝试执行Month(Collect_Date) 时,我也遇到了不同的错误。因此,如果有人知道为什么,我将不胜感激。我附上了一张图片,上面有我得到的代码和结果。

【问题讨论】:

从不FROM 子句中使用逗号。 始终使用正确、明确、标准JOIN语法。 'Collect_Date'&gt;=2016-1-1?这与'Collect_Date'&gt;=2014 相同如何 文字字符串 'Collect Date' 具有比整数 2014 更大的值?我怀疑你的意思是Collect_Date &gt;= '20160101' 并且,为了扩展 Gordan 的观点:Bad habits to kick : using old-style JOINs。 很高兴知道加入我会调整它。感谢您的链接。我正在尝试使收集日期大于或等于 2016 年。我尝试使用它,但它没有放入过滤器,它显示了所有日期。我认为我的日期转换有问题。 我认为您在使用 CollectDate 时遇到的问题仅仅是您在 WHERE 子句中使用它,该子句在定义它的 SELECT 子句之前被评估。它在评估 WHERE 子句时根本不存在。见***.com/questions/21693208/… 【参考方案1】:

我知道发生了什么,您正试图在 select 语句中使用别名。你不能那样做,cmets 中已经涵盖了其他一些问题,但这里是问题的直接答案:

Select  Location_ID 
  , Convert(Date,CONVERT(varchar(10),Collect_Month_Key,101)) as Collect_Date 
  , Calc_Gross_Totals
  , Loc_Country 
  , CONVERT(varchar(8),Collect_Month_Key)+'-'+Location_ID as [Unique Key]
From FT_GPM_NPM_CYCLES
  , LU_Location
  , LU_Loc_Country
Where LU_Location.LU_Loc_Country_Key=LU_Loc_Country.LU_Loc_Country_Key
  and FT_GPM_NPM_CYCLES.Lu_Loc_Key= LU_Location.LU_Loc_Key
  and Collect_Month_Key <> -1 
  and Convert(Date,CONVERT(varchar(10),Collect_Month_Key,101)) >= '2016-1-1'
Order By Location_ID, Collect_Date;

【讨论】:

哇,明白了。我看到你做了什么。我已经对早期建议的连接进行了调整。我现在在 FROM 语句上做左连接而不是“,”。所以我的最后一个问题是,当我将其添加到选择语句MONTH('Collect_Date') 以尝试获取收集月份时,我收到此错误“从字符串转换日期和/或时间时转换失败”。我是否需要将 Collect_Date 转换回 int 才能执行 MONTH 我想通了。我这样做了:MONTH(Convert(Date,CONVERT(varchar(10),Collect_Month_Key,101))) as MONTH【参考方案2】:

这是一个更新后的查询,它带来了以下修改:

正如 Robert Sheahan 所说,您不能在 WHERE 子句中使用结果集列别名

正如 Larnu 所说,由于您将日期存储为字符串,您可以简单地进行 字符串比较 来过滤记录(并返回字符串值)。使用这种技术,您不需要附加条件Collect_Month_Key &lt;&gt; -1,因为字符串'-1' 不大于字符串'20160101'

使用显式连接而不是隐式连接(Gordon Linoff 评论)

我添加了表别名:它们使查询更易于阅读(并使自联接表成为可能...)

我还建议为查询中使用的 all 列加上它们的表别名。这清楚地表明每列来自哪个表,并使查询更易于理解和维护。注意:如果Collect_Month_Key 属于FT_GPM_NPM_CYCLES 以外的表,您希望将条件从WHERE 子句移动到相关ON 子句的ON 子句中)

查询:

SELECT
    Location_ID, 
    Collect_Month_Key AS Collect_Date, 
    Calc_Gross_Totals, 
    Loc_Country, 
    CONVERT(varchar(8),Collect_Month_Key) + '-' + Location_ID AS Unique_Key
FROM 
    FT_GPM_NPM_CYCLES AS cyc
    INNER JOIN LU_Location AS loc
        ON cyc.Lu_Loc_Key = loc.LU_Loc_Key
    INNER JOIN LU_Loc_Country AS cty
        ON loc.LU_Loc_Country_Key = cty.LU_Loc_Country_Key
WHERE 
    Collect_Month_Key > '20160101'
ORDER BY 
    Location_ID, 
    Collect_Month_Key

【讨论】:

谢谢,这是对所有内容的很好总结,而且不那么复杂。我很感激。 欢迎@kevinh! 也许我对日期有点迂腐(也许这是我无情的 Oracle 背景)。如果Collect_Month_Key 是一个日期,那么我建议在WHERE 子句中使用之前将硬编码值'20160101' 显式转换为日期。【参考方案3】:

要回答您的评论“因此,如果我不将 collect_Date 放在 WHERE 中,将来我应该将它放在哪里?”,我建议使用 Common Table Expressions。从功能上讲,它们等同于在 FROM 子句中定义派生表,但它们将其移动到“上方”​​,因此感觉更像“之前”,我认为它们更容易阅读。要将 GMB 的出色解决方案转换为使用 CTE:

--Leading ; because CTEs require prvious command terminated explicitly
;WITH cteWithDates as ( --cteDates becomes a virtual temporary table
    SELECT
        cyc.* --Keep all the original columns of FT_GPM_NPM_CYCLES
        , Collect_Month_Key AS Collect_Date --and add Collect_Date and Unique_Key
        , CONVERT(varchar(8),Collect_Month_Key) + '-' + Location_ID AS Unique_Key
    FROM FT_GPM_NPM_CYCLES AS cyc
) --you could add more CTEs with the following format, 
--all become available at the end
--, cteMore as (SELECT ... FROM ...)
--the first line after the closing ) has access to all CTEs, but ONLY that line
SELECT Location_ID, 
    Collect_Date, 
    Calc_Gross_Totals, 
    Loc_Country, 
    Unique_Key
FROM 
    cteWithDates AS cyc --Use the CTE as you would your original table, 
    --but the added fields are now available EVERYWHERE in your query!
        INNER JOIN LU_Location AS loc
            ON cyc.Lu_Loc_Key = loc.LU_Loc_Key
        INNER JOIN LU_Loc_Country AS cty
            ON loc.LU_Loc_Country_Key = cty.LU_Loc_Country_Key
WHERE 
    Collect_Date > '20160101' --NOW you can use CollectDate!
ORDER BY 
    Location_ID, 
    Collect_Date --And here too

请注意,这比使用#TableName 定义一个实际的临时表效率更高,因为查询优化器可以从 CTE 中删除未使用的记录,但它必须将它们全部放入 #temporary 表中,如果您使用的是表很大,匹配的子集很小。

【讨论】:

以上是关于将 varchar 值“Collect_Date”转换为数据类型 int 时转换失败的主要内容,如果未能解决你的问题,请参考以下文章

将 varchar 值“%”转换为数据类型 int 时转换失败

将充满逗号分隔值的 varchar 传递给 SQL Server IN 函数

如何将存储为 VARCHAR 的 UTC 日期时间值转换为常规日期时间

将 varchar 数据类型转换为 datetime 数据类型导致值超出范围的问题

将 varchar 值“AND ID =”转换为数据类型 int 时转换失败

将 varchar 值“A0001”转换为数据类型 int 时转换失败