这是我的问题:
SELECT
*
FROM
(SELECT
A.Name, AP.PropertyName, APV.Value AS [PropertyValue],
CONVERT(DATETIME, APV.VALUE, 101) AS [DateValue]
FROM dbo.Account AS A
JOIN dbo.AccountProperty AS AP ON AP.AccountTypeId = A.AccountTypeId
JOIN dbo.AccountPropertyValue AS APV ON APV.AccountPropertyId = APV.AccountPropertyId
AND APV.AccountId = A.AccountId
WHERE
A.AccountTypeId = '19602AEF-27B2-46E6-A068-7E8C18B0DD75' --VENDOR
AND AP.PropertyName LIKE '%DATE%'
AND ISDATE(APV.Value) = 1
AND LEN(SUBSTRING( REVERSE(APV.Value), 0 , CHARINDEX( '/', REVERSE(APV.Value)))) = 4 --ENSURE 4 digit year
) AS APV
WHERE
APV.DateValue < GETDATE()
导致以下错误:
从字符串转换日期和/或时间时转换失败。
如果您注释掉WHERE APV.DateValue < GETDATE()
子句,则没有错误,我得到300多行。当我启用WHERE
子句时,我收到错误。
所以你要告诉我我的数据是否正确?这就是我的想法,所以我试图弄清楚数据中的问题所在,所以我开始使用TOP()
来隔离位置。问题是,一旦我使用TOP()
函数,错误消失了,我只有2000行数据开始。所以我在内部TOP(99999999)
上放了一个荒谬的SELECT
,现在整个查询都有效。
内部SELECT
返回相同数量的行,包含或不包含TOP()
。
WHY ???
仅供参考,这是有效的SQL:
SELECT
*
FROM
(SELECT TOP(99999999)
A.Name, AP.PropertyName, APV.Value AS [PropertyValue],
CONVERT(DATETIME, APV.VALUE, 101) AS [DateValue]
FROM dbo.Account AS A
JOIN dbo.AccountProperty AS AP ON AP.AccountTypeId = A.AccountTypeId
JOIN dbo.AccountPropertyValue AS APV ON APV.AccountPropertyId = APV.AccountPropertyId
AND APV.AccountId = A.AccountId
WHERE
A.AccountTypeId = '19602AEF-27B2-46E6-A068-7E8C18B0DD75' --VENDOR
AND AP.PropertyName LIKE '%DATE%'
AND ISDATE(APV.Value) = 1
AND LEN(SUBSTRING(REVERSE(APV.Value), 0 , CHARINDEX( '/', REVERSE(APV.Value)))) = 4
) AS APV
WHERE
APV.DateValue < GETDATE()
答案 0 :(得分:0)
我的猜测是,您的日期是APV.VALUE
还包含无法转换为日期的数据,应该使用其他条件过滤掉吗?
由于SQL Server可以决定使用您给出的条件首先限制数据:
APV.DateValue < CONVERT( DATETIME, GETDATE(),101)
如果有数据无法转换为日期,那么您将收到错误。
为了更清楚,这就是被过滤的内容:
CONVERT( DATETIME, APV.VALUE, 101) AS [DateValue]
如果有任何数据无法使用101格式转换为日期,则使用getdate()的过滤器将失败,即使该行未包含在最终结果集中,例如因为AP.PropertyName
不包含DATE
。
由于您使用的是SQL Server 2012,因此使用try_convert代替转换可以解决您的问题
为什么它适用于顶级?在这种情况下,SQL Server无法使用外部查询中的条件,因为结果可能会更改,因为它可能会影响顶部返回的行数
答案 1 :(得分:0)
您面临的问题是SQL Server可以在查询处理期间随时评估表达式 - 甚至在评估WHERE
子句之前。这对性能来说可能是一个很大的好处。但是,结果是错误可以由不在最终结果集中的行生成。 (除零以及转换错误也是如此。)
幸运的是,SQL Server解决了转换问题。使用try_convert()
:
TRY_CONVERT( DATETIME, APV.VALUE, 101) AS [DateValue]
如果出现问题,则返回NULL而不是错误。
某些版本的工作原因和其他版本的原因并不是因为执行顺序。实际上还没有一种方法可以预测哪些有效,哪些无效 - 如果查询的执行计划因其他原因(例如表统计信息)而发生变化,则可能会发生变化。因此,请使用try_convert()
。
答案 2 :(得分:0)
因为表中的记录数&lt; 999..99。关于错误,似乎SQL引擎在转换为日期后评估WHERE子句,因此您可以尝试这样做:
SELECT *
FROM (
SELECT A.Name
, AP.PropertyName
, APV.Value AS [PropertyValue]
,
CASE
WHEN SDATE(APV.Value) = 1
THEN CONVERT( DATETIME, APV.VALUE, 101)
ELSE NULL
END AS [DateValue]
FROM dbo.Account AS A
JOIN dbo.AccountProperty AS AP
ON AP.AccountTypeId = A.AccountTypeId
JOIN dbo.AccountPropertyValue AS APV
ON APV.AccountPropertyId = APV.AccountPropertyId
AND APV.AccountId = A.AccountId
WHERE A.AccountTypeId = '19602AEF-27B2-46E6-A068-7E8C18B0DD75' --VENDOR
AND AP.PropertyName LIKE '%DATE%'
AND LEN( SUBSTRING( REVERSE(APV.Value), 0 , CHARINDEX( '/', REVERSE(APV.Value)))) = 4 --ENSURE 4 digit year
) AS APV
WHERE APV.DateValue IS NOT NULL AND APV.DateValue < GETDATE()