将 varchar 数据类型转换为 datetime 数据类型导致值超出范围的问题
Posted
技术标签:
【中文标题】将 varchar 数据类型转换为 datetime 数据类型导致值超出范围的问题【英文标题】:Problem with The conversion of a varchar data type to a datetime data type resulted in an out-of-range value 【发布时间】:2020-10-29 11:33:05 【问题描述】:我在 SQL 服务器中执行此 SQL 请求时收到此消息,
将 varchar 数据类型转换为 datetime 数据类型导致值超出范围。
这是我的 SQL 请求:
set language english
SELECT DISTINCT TOP (10000)
ROW_NUMBER() OVER (PARTITION BY TPP.NoPersonne,
TROC.reftiers,
CONVERT(datetime, TSIT.DateAffiliation, 120),
CONVERT(datetime, COALESCE(TSIT.DateSortie, '31/12/9999'), 120)
ORDER BY CONVERT(datetime, COALESCE(TCT.DateFinValidite, '31/12/9999'), 120) DESC) AS RowCount1,
ROW_NUMBER() OVER (PARTITION BY TPP.NoPersonne,
TROC.reftiers,
CONVERT(datetime, TSIT.DateAffiliation, 120),
CONVERT(datetime, COALESCE(TSIT.DateSortie, '31/12/9999'), 120)
ORDER BY CONVERT(datetime, COALESCE(TP.DateFin, '31/12/9999'), 120) DESC) AS RowCount2
FROM stock.TPersonnePhysique TPP
INNER JOIN [dbo].[ZED_PP_ACTIVE] PPA ON TPP.OID = PPA.OID_PP
INNER JOIN stock.TRoleAssure TRO ON TPP.oid = TRO.reftiers
AND TPP.flag_delete = 0
AND TRO.flag_delete = 0
INNER JOIN stock.TSitContractAff TSIT ON TRO.oid = TSIT.refroletiers
AND TSIT.flag_delete = 0
AND CONVERT(datetime, ISNULL(TSIT.DateSortie, '01/01/9999'), 120) > DATEADD(YEAR, -3, GETDATE())
INNER JOIN stock.TLienContratAdherentCol TLI ON TCON.RefLienContratAdherentColl = TLI.oid
AND TLI.flag_delete = 0
LEFT JOIN(stock.TRattachementPopulation TRP
INNER JOIN stock.JDonneesComplementaires_RattPop JDC_RP ON JDC_RP.RefRattachementPopulation = TRP.OID
AND JDC_RP.Flag_Delete = 0
AND TRP.Flag_Delete = 0
INNER JOIN stock.TContratTravail TCT ON TCT.OID = JDC_RP.ListDonneesComplementaires
AND TCT.Flag_Delete = 0
AND TCT.CategorieProfessionnelle <> ''
AND TCT.CategorieProfessionnelle IS NOT NULL)ON TRP.RefMembre = TRO.OID
AND ((CONVERT(datetime, TCT.DateDebutValidite, 120) >= CONVERT(datetime, TSIT.DateAffiliation, 120)
AND CONVERT(datetime, TCT.DateDebutValidite, 120) <= CONVERT(datetime, COALESCE(TSIT.DateSortie, '2999-12-31'), 120))
OR (CONVERT(datetime, TSIT.DateAffiliation, 120) >= CONVERT(datetime, TCT.DateDebutValidite, 120)
AND CONVERT(datetime, TSIT.DateAffiliation, 120) < CONVERT(datetime, COALESCE(TCT.DateFinValidite, '2999-12-31'), 120)));
我想修复这条消息:(
【问题讨论】:
SELECT DISTINCT TOP (1)
没有ORDER BY
? TOP 1
何时会产生超过 1 个不同的行(提示:它不会)并且您真的对您的解决方案返回任意行感到满意吗?
显示示例输入数据和所需的输出,并解释为什么会这样映射。
至于问题,像AND ((CONVERT(datetime, TCT.DateDebutValidite, 120) >= CONVERT(datetime, TSIT.DateAffiliation, 120)
这样的子句strongly意味着TCT.DateDebutValidite
和TSIT.DateAffiliation
没有存储为datetime
;那是你的真正的问题。修复设计; varchar
不是一种适合所有数据类型的尺寸。
这只是一个例子,查询返回超过 2300 万行。
"这只是示例" 那么为什么要在查询中没有 DISTINCT TOP(1)
时添加它?这只会使您的问题脱轨,而这两者的结合,加上缺少ORDER BY
很有可能使您的问题脱轨。
【参考方案1】:
不要将日期存储为字符串!它只会导致诸如此类的问题。
解决错误的一种方法是使用try_convert()
:
try_convert(datetime, TSIT.DateAffiliation, 120)
这不是失败,而是返回NULL
,因此结果将被过滤掉。
您可以使用以下方法找到违规值:
select TSIT.DateAffiliation
from stock.TSitContractAff TSIT
where try_convert(datetime, TSIT.DateAffiliation, 120) is null and
TSIT.DateAffiliation is not null;
注意:您需要对查询中的所有日期执行此操作。你真的应该把这些精力放在修复数据模型上,而不是修复查询上。也就是说,使用正确的日期/时间数据类型,而不是字符串。
【讨论】:
以上是关于将 varchar 数据类型转换为 datetime 数据类型导致值超出范围的问题的主要内容,如果未能解决你的问题,请参考以下文章
即使没有 datetime 列,也获取“将 varchar 数据类型转换为 datetime 数据类型导致超出范围的值”
将 varchar 2007-12-19-11.57.17.366731 转换为 datetime 数据类型
Polybase - 将数据类型 VARCHAR 转换为 DATETIME 时出错
如何解决“将 varchar 数据类型转换为 datetime 数据类型导致值超出范围。”错误
消息 242:将 varchar 数据类型转换为 datetime 数据类型导致值超出范围
System.Data.SqlClient.SQLException:将 varchar 数据类型转换为 datetime