从表中选择一列包含许多数据类型作为varchar

时间:2017-04-28 15:47:30

标签: sql-server

我有一个日志表,它将表中数据的变化记录到不同数据类型的多个字段中。它保存字段名称,保存值之前和之后等等。数据表如下所示:

FieldName     Before      After

Category        lx           mt
AskingPrice   9.50        10.00
Name          Paul        Paula
AskingPrice   7.20         9.10
Category        za           pz

因此,Before和After列中的数据类型会有所不同。当我尝试编写一个查询以选择字段= AskingPrice的位置并且After值大于Before值时,它会因数据类型转换而出错。在错误之后它确实给出了正确的结果,但我想错误是它预先检查列中的数据类型但是选择了第一行..我使用的SQL是:

SELECT FieldName, Before, After
FROM   Table WHERE Field = 'dblAskingPrice' and Before > After

即使我将值转换为错误..

SELECT FieldName, Before, After FROM Table WHERE Field = 'dblAskingPrice' and 
Cast(Before as Numeric) > Cast(After as Numeric)

现在我可以在另一个内部选择选择字段,第二个选择进行投射和比较但我们的软件不允许选择一个选择语句。

有没有办法可以在一个select语句中得到这个而没有错误?

2 个答案:

答案 0 :(得分:2)

SQL数据库不保证评估WHERE子句中的订单项。

我再说一遍:SQL数据库不保证评估WHERE子句中的订单项。

数据库通常会查看每个条件并尝试按照它认为会产生结果最快最便宜的顺序应用条件,而不是在SQL命令中显示订单项。 ...通常情况下,首先会应用与索引最匹配或限制最多的项目,其他项目将在稍后发布。但是你也不能依赖这种行为,因为查询优化器可以根据当时的统计数据和负载做出奇怪和意外的事情。

这意味着可以在评估Cast(Before as Numeric)表达式之前尝试Field = 'dblAskingPrice' ,该表达式将您限制为您认为可以安全投放的记录。

您可以通过在FieldName,Before,After上设置一个好的索引来影响这一点,但是您无法保证这一点,特别是考虑到CAST()操作通常与索引不匹配。 Filtered Index也可能有所帮助,但同样:它不能保证。

您有时可以使用嵌套查询,CTE或仅包含特定记录的视图来解决此问题:

SELECT FieldName, Before, After
FROM (
    SELECT *
    FROM   [Table] 
    WHERE FieldName = 'dblAskingPrice'
) x
WHERE Cast(Before as Numeric) > Cast(After as Numeric)

但这里最好的解决方案通常涉及修复损坏的架构。在这种情况下,我建议修复架构的方法是完全删除表,而是启用更改数据捕获功能(从Sql Server 2016 SP1开始)现在是Sql Server Standard Edition的一部分,并使用审计功能内置于Sql Server。

答案 1 :(得分:1)

您可以在此处使用cte首先过滤掉您关注的行。然后你可以将它转换为十进制。这样的事情。

{{1}}