Alp*_*pha 10 sql datetime where-clause sql-server-2008
我遇到了一些SQL服务器查询的问题.事实证明我有一个带有"Attibute_Name"和"Attibute_Value"字段的表,它可以是任何类型,存储在varchar中.(是的,我知道.)
特定属性的所有日期似乎都存储在"YYYY-MM-DD hh:mm:ss"格式中(不是100%确定,这里有数百万条记录),所以我可以毫无问题地执行此代码:
select /*...*/ CONVERT(DATETIME, pa.Attribute_Value)
from
ProductAttributes pa
inner join Attributes a on a.Attribute_ID = pa.Attribute_ID
where
a.Attribute_Name = 'SomeDate'
Run Code Online (Sandbox Code Playgroud)
但是,如果我执行以下代码:
select /*...*/ CONVERT(DATETIME, pa.Attribute_Value)
from
ProductAttributes pa
inner join Attributes a on a.Attribute_ID = pa.Attribute_ID
where
a.Attribute_Name = 'SomeDate'
and CONVERT(DATETIME, pa.Attribute_Value) < GETDATE()
Run Code Online (Sandbox Code Playgroud)
我将收到以下错误: 从字符串转换日期和/或时间时转换失败.
怎么会在where子句上失败而不是在select子句上?
另一个线索:
如果不使用Attribute_Name进行过滤,而是使用存储在数据库(PK)中的实际Attribute_ID,它将正常工作.
select /*...*/ CONVERT(DATETIME, pa.Attribute_Value)
from
ProductAttributes pa
inner join Attributes a on a.Attribute_ID = pa.Attribute_ID
where
a.Attribute_ID = 15
and CONVERT(DATETIME, pa.Attribute_Value) < GETDATE()
Run Code Online (Sandbox Code Playgroud)
更新 感谢大家的答案.我发现很难真正选择正确的答案,因为每个人都指出了一些对理解问题有用的东西.这绝对与执行的顺序有关.事实证明我的第一个查询正常工作,因为首先执行WHERE子句,然后执行SELECT.由于相同的原因,我的第二个查询失败(因为未过滤属性,执行相同的WHERE子句时转换失败).我的第三个查询是有效的,因为ID是索引(PK)的一部分,所以它优先,并且首先在该条件下钻取结果.
谢谢!
您似乎在假设某种短路评估或保证WHERE
条款中的谓词排序.这不保证.如果列中有混合数据类型,那么处理它们的唯一安全方法是使用CASE
表达式.
使用(例如)
CONVERT(DATETIME,
CASE WHEN ISDATE(pa.Attribute_Value) = 1 THEN pa.Attribute_Value END)
Run Code Online (Sandbox Code Playgroud)
不
CONVERT(DATETIME, pa.Attribute_Value)
Run Code Online (Sandbox Code Playgroud)
如果转换位于 WHERE 子句中,则可能会评估比出现在投影列表中更多的记录(值)。我之前已经在不同的上下文中讨论过这个问题,请参阅T-SQL 函数并不暗示一定的执行顺序和On SQL Server booleanoperatorshort-circle。你的情况更简单,但很相似,最终的根本原因是相同的:在处理像 SQL 这样的声明性语言时,不要假设命令式执行顺序。
从很大程度上来说,最好的解决方案是清理数据并将列类型更改为 DATETIME 或 DATETIME2 类型。所有其他解决方法都会有一个或另一个缺点,因此您最好只做正确的事情。
更新
经过仔细观察(抱歉,我是@VLDB,并且只在会话之间查看),我意识到您有一个具有固有的无类型语义的 EAV 存储(可以是attribute_value
字符串、日期、整数等)。我的观点是,最好的选择是在存储中使用sql_variant
并一直到客户端(即项目sql_variant
)。您可以在客户端中凝聚类型,所有客户端 API 都有从 a 中提取内部类型的方法sql_variant
,请参阅使用 sql_variant 数据(好吧,几乎所有客户端 API...在 CLR 中使用 sql_variant 数据类型)。您sql_variant
可以存储多种类型,而无需处理字符串表示形式的问题,您可以用来SQL_VARIANT_PROPERTY
检查存储值中的内容BaseType
,甚至可以像检查约束一样思考以强制数据类型的正确性。
归档时间: |
|
查看次数: |
14459 次 |
最近记录: |