此查询从tblValue返回一组日期,其FieldValue类型为nvarchar(4000)
SELECT t1.FieldValue FROM (SELECT FieldValue
FROM tblValue
WHERE FieldID = 4) t1
WHERE DateAdd(day, -90, t1.FieldValue) <= GETDATE()
这样做有效,但我不想对4的FieldID进行硬编码,而是希望得到所有类型为&#34; Expiration&#34;的FieldValues。 此查询返回4.
SELECT FieldID FROM tblField WHERE FieldType = 'Expiration'
所以,我希望这个查询的最里面的子查询返回4,然后将DateAdd仅应用于从最外面的子查询中的t1产生的那些Expiration值,这是在第一个例子中发生的情况
SELECT t1.FieldValue FROM (SELECT FieldValue
FROM tblValue
WHERE FieldID = (SELECT FieldID FROM tblField WHERE FieldType = 'Expiration')) t1
WHERE DateAdd(day, -90, t1.FieldValue) <= GETDATE()
但是我收到了错误
&#34;从字符串转换日期和/或时间时转换失败。&#34;
对我来说,建议将DateAdd应用于tblValue的所有值,而不仅仅应用于返回t1的子查询所产生的值。这可能是技术上的原因,但它对我来说似乎并不合适。出于某种原因
WHERE FieldID = 4) t1
不等于
WHERE FieldID = (SELECT FieldID FROM tblField WHERE FieldType = 'Expiration')) t1
碰巧的是,如果我放弃错误查询的最后WHERE子句,我会得到与工作查询中相同的日期集。所以t1不应该呈现DateAdd应该有问题的任何值。但它确实如此。我很困惑为什么。
答案 0 :(得分:3)
这是因为优化程序生成的特定执行计划。根据它选择如何组合各个子句的比较和过滤操作,它可以先做一个或另一个。
在这种情况下,它会在应用FieldType过滤器之前尝试执行日期转换和比较。
这是一个众所周知的问题,但SQL优化器的行为是固有的 - 这是一个类似的问题,具有不同的数据类型:https://connect.microsoft.com/SQLServer/feedback/details/333312/error-8114-converting-data-type-varchar-to-numeric
有很多方法,但它们并不总是直截了当,通常要求你强制执行特定的执行顺序。
以下对我有用,虽然我知道CASE技术并不总是100%有效。来自this fiddle:
SELECT t1.FieldValue FROM (SELECT FieldValue
FROM tblValue
WHERE FieldID = (SELECT FieldID FROM tblField WHERE FieldType = 'Expiration')) t1
WHERE CASE WHEN ISDATE(t1.FieldValue) = 1 THEN DateAdd(day, -90, t1.FieldValue) ELSE '1/1/2900' END <= GETDATE()
答案 1 :(得分:0)
我想你想要这个?
SELECT * FROM tblValue v
JOIN tblField f ON v.FieldID = f.FieldID
WHERE f.FieldType = 'Expiration' AND DateAdd(day, -90, v.FieldValue) <= GETDATE()
答案 2 :(得分:0)
将此分类为错误应用不公平
您无法控制TSQL将评估哪些行
有了一个很难4,优化器首先做了
没有硬4,查询优化器必须为任何事情做好准备并将其移至后期
查询优化器甚至考虑派生的表公平游戏来优化
如果您只是查看查询计划,就可以看到订单
尝试
SELECT *
FROM tblValue v
JOIN tblField f
ON v.FieldID = f.FieldID
AND f.FieldType = 'Expiration'
AND DateAdd(day, -90, v.FieldValue) <= GETDATE()