提问人:CGSD 提问时间:9/14/2022 最后编辑:Dale KCGSD 更新时间:9/14/2022 访问量:124
WHERE 子句中的执行顺序不允许 varchar AS 日期的 CAST
Order of execution in WHERE clause not allowing CAST of varchar AS date
问:
我有如下表格:
名称:VW_Questionnaire
问卷 Id (int) (pk) | QuestionId (整数) | 问题 (varchar) | 响应 (varchar) | 标记 (varchar) |
---|---|---|---|---|
1 | 1 | 你有多少节课? | 4 | 零 |
2 | 2 | 你上课的第一天是什么时候? | 2022-09-01 | SP1系列 |
3 | 1 | 你有多少节课? | 9 | 零 |
4 | 2 | 你上课的第一天是什么时候? | 2022-10-01 | SP1系列 |
以下代码有效:
SELECT Question, Response
From VW_Questionnaire
WHERE QuestionId = 2
AND CAST(Response AS Date) < SELECT (CURRENT_TIMESTAMP)
以下代码引发错误:
SELECT Question, Response
From VW_Questionnaire
WHERE Tag = 'SP1'
AND CAST(Response AS Date) < SELECT (CURRENT_TIMESTAMP)
从字符串转换日期和/或时间时转换失败。
似乎在第一个示例中,它首先过滤到 WHERE QuestionId = 2,然后它可以成功地将响应 CAST AS Date 强制转换为日期。
但是,在第二个示例中,它似乎在筛选到 WHERE Tag = 'SP1' 之前尝试 CAST Response AS Date。
我什至尝试使用 CTE 执行此操作,其中在 CTE 中,我对 WHERE Tag = 'SP1' 进行过滤,然后从这个过滤表和 CAST 响应 AS 日期中进行选择。我仍然遇到转换错误。
知道为什么会这样吗?
答:
1赞
Charlieface
9/14/2022
#1
SQL 是一种声明性语言。这意味着服务器可以自由地对谓词进行重新排序,以便达到索引并提高性能。
因此,不能依赖按从左到右顺序执行的谓词。相反,您可以只使用 ,这将清除任何无效值TRY_CAST
SELECT Question, Response
FROM VW_Questionnaire
WHERE QuestionId = 2
AND TRY_CAST(Response AS Date) < CURRENT_TIMESTAMP;
请注意,关于重新排序的观点甚至适用于派生的表和视图。例如,在此版本中,您可能仍会收到错误:
SELECT Question, Response
FROM (
SELECT *
FROM VW_Questionnaire
WHERE QuestionId = 2
) v
WHERE CAST(Response AS Date) < CURRENT_TIMESTAMP;
唯一保证从左到右计算的构造是(即使这种保证也仅适用于标量值,而不适用于聚合)。CASE
我强烈建议您首先确保您的数据格式正确,这样您就不需要强制转换它。
评论
0赞
CGSD
9/14/2022
TRY_CAST是一个可行的选项。响应是一个通用字段,它根据许多问题收集数据,这些问题的响应可以从文本响应、日期、布尔值、整数等格式化。回答将始终针对问题类型进行适当的格式设置,但所有回答都属于同一个“响应”字段。也许这个 Response 表有更好的设计,但就目前而言,TRY_CAST允许筛选器根据需要执行。
0赞
Dale K
9/14/2022
@CGSD,是的,更好的(恕我直言)答案表设计是您可能期望的每种答案类型的一列,例如字符串、数字、布尔值、日期时间。这使您可以更好地控制查询等。
0赞
Charlieface
9/14/2022
@CGSD 这也是我建议的(以及确保一次只有一个可能的字段不为空的约束)。在紧要关头,您也可以使用柱子来执行此操作,但那时您仍然需要。CHECK
sql_variant
TRY_CAST
0赞
CGSD
9/14/2022
@DaleK我同意你的看法,但不确定如何设置这样的东西。我基本上有一个问题表和一个回答表,然后将它们绑定到一个视图中。这些问题由不同的用户重复和多次回答。我创建了一个视图,可以将响应表与问题表相关联,而不必每次都重复问题,而只需引用 QuestionId。也许解决方案是为每个响应数据类型创建大量响应表,然后将所有结果合并到一个视图中?
0赞
Dale K
9/14/2022
我不会使用单独的表,使用单独的列。然后将您期望的答案类型(字符串、数字等)存储为问题的一部分,然后,如果您需要将结果作为一列进行查看,请使用事写表达式来确定要显示的列。
评论
CURRENT_TIMESTAMP
SELECT (CURRENT_TIMESTAMP)