Main T-SQL WHERE 函数似乎错误地应用于子查询
Main T-SQL WHERE function seems to be wrongly applied to a subquery
此查询return是来自 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 进行硬编码,而是希望获取类型为 "Expiration" 的字段的所有 FieldValue。
此查询 returns 4.
SELECT FieldID FROM tblField WHERE FieldType = 'Expiration'
因此,我希望此查询的最内层子查询为 return 4,然后将 DateAdd 仅应用于从最外层子查询中的 t1 产生的那些过期值,这就是工作中发生的情况第一个例子。
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()
但是我得到了错误
"Conversion failed when converting date and/or time from character string."
这对我来说表明 DateAdd 被应用于 tblValue 的所有值,而不仅仅是那些由 returns t1 的子查询产生的值。可能有技术原因,但对我来说似乎不正确。出于某种原因
WHERE FieldID = 4) t1
不等同于
WHERE FieldID = (SELECT FieldID FROM tblField WHERE FieldType = 'Expiration')) t1
碰巧的是,如果我省略错误查询的最后一个 WHERE 子句,我会得到与工作查询中相同的一组日期。所以 t1 不应该呈现 DateAdd 应该有问题的任何值。但它就在那里。我不明白为什么。
我猜你想要这个?
SELECT * FROM tblValue v
JOIN tblField f ON v.FieldID = f.FieldID
WHERE f.FieldType = 'Expiration' AND DateAdd(day, -90, v.FieldValue) <= GETDATE()
这是因为优化器生成的特定执行计划。根据它选择如何组合各种子句的比较和过滤操作,它可以先做一个或另一个。
在这种情况下,它会尝试在应用 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()
将其归类为错误应用是不公平的
您无法控制 TSQL 将计算哪些行
对于硬 4,优化器首先执行此操作
如果没有硬 4,查询优化器必须为任何事情做好准备并将其移至稍后
查询优化器甚至考虑派生 table 公平游戏来优化
如果你只看查询计划,你可以看到顺序
尝试
SELECT *
FROM tblValue v
JOIN tblField f
ON v.FieldID = f.FieldID
AND f.FieldType = 'Expiration'
AND DateAdd(day, -90, v.FieldValue) <= GETDATE()
此查询return是来自 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 进行硬编码,而是希望获取类型为 "Expiration" 的字段的所有 FieldValue。 此查询 returns 4.
SELECT FieldID FROM tblField WHERE FieldType = 'Expiration'
因此,我希望此查询的最内层子查询为 return 4,然后将 DateAdd 仅应用于从最外层子查询中的 t1 产生的那些过期值,这就是工作中发生的情况第一个例子。
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()
但是我得到了错误
"Conversion failed when converting date and/or time from character string."
这对我来说表明 DateAdd 被应用于 tblValue 的所有值,而不仅仅是那些由 returns t1 的子查询产生的值。可能有技术原因,但对我来说似乎不正确。出于某种原因
WHERE FieldID = 4) t1
不等同于
WHERE FieldID = (SELECT FieldID FROM tblField WHERE FieldType = 'Expiration')) t1
碰巧的是,如果我省略错误查询的最后一个 WHERE 子句,我会得到与工作查询中相同的一组日期。所以 t1 不应该呈现 DateAdd 应该有问题的任何值。但它就在那里。我不明白为什么。
我猜你想要这个?
SELECT * FROM tblValue v
JOIN tblField f ON v.FieldID = f.FieldID
WHERE f.FieldType = 'Expiration' AND DateAdd(day, -90, v.FieldValue) <= GETDATE()
这是因为优化器生成的特定执行计划。根据它选择如何组合各种子句的比较和过滤操作,它可以先做一个或另一个。
在这种情况下,它会尝试在应用 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()
将其归类为错误应用是不公平的
您无法控制 TSQL 将计算哪些行
对于硬 4,优化器首先执行此操作
如果没有硬 4,查询优化器必须为任何事情做好准备并将其移至稍后
查询优化器甚至考虑派生 table 公平游戏来优化
如果你只看查询计划,你可以看到顺序
尝试
SELECT *
FROM tblValue v
JOIN tblField f
ON v.FieldID = f.FieldID
AND f.FieldType = 'Expiration'
AND DateAdd(day, -90, v.FieldValue) <= GETDATE()