将 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'>=2016-1-1
?这与'Collect_Date'>=2014
相同如何 文字字符串 'Collect Date'
具有比整数 2014
更大的值?我怀疑你的意思是Collect_Date >= '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 <> -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 数据类型导致值超出范围的问题