【问题标题】:EXCEPT returning unpredictable results除了返回不可预测的结果
【发布时间】:2015-08-01 21:07:19
【问题描述】:

我有一张表 DB_Budget,它有 3 列 Business_Unit_CodeLedger_PeriodBudget_GBP。为简单起见,我省略了其他列。

数据类型是 -

此表存在于我的开发和生产环境中。

在进行一些质量检查时,我运行了以下查询:

select 
Business_Unit_Code,
Ledger_Period,
Budget_GBP
from [SomeLinkedServer].[Database].dbo.DB_BUDGET
where business_unit_code = 'AV' and ledger_period = '200808'
and budget_gbp >= 32269

except

select 
Business_Unit_Code,
Ledger_Period, 
Budget_GBP
from [Database].dbo.DB_BUDGET
where business_unit_code = 'AV' and ledger_period = '200808'
and budget_gbp >= 32269

我明白了 -

如果我删除了例外,这就是我得到的 -

显然,两个表中的数据相同!为什么EXCEPT 会给我一排?

事情变得有趣。我将Budget_GBP 包裹在LTRIM(RTRIM( ... 构造周围。 和事情匹配!

我做了一点googling 并发现LTRIM(RTRIM( 基本上将浮点数四舍五入到32269.2。这可能是它们匹配的原因。

所以,总而言之,我的第一个问题是为什么EXCEPT 在记录匹配时会在结果中显示一行?

我的第二个问题可能很简单。如您所见,我被限制在WHERE 子句中使用子句budget_gbp >= 32269。原因是当我提供确切的值(我从 SSMS 复制)时,我没有得到任何结果。请让我知道我在这里做错了什么。

编辑 - 有什么方法可以进行数据验证吗?数据库中有 100 个表,我几乎不可能清除浮动列并将它们包裹在演员表中。使用 EXCEPT 是在开发环境中验证数据的一种方法。

【问题讨论】:

  • @dnoeth 当然,问题是像“预算”这样的字段真的应该是近似值。
  • @Conrad Frix:是的,因此应该考虑切换到确切的数字:-)
  • 正如@dnoeth 所暗示的,您是否使用numberdecimal 类型来存储Budget_GBP 值?如果不是,您可能会使用类似于科学记数法存储/计算的浮点数,您可能会在其中发生意想不到的事情。另一种可能性是字符串值可能在值的末尾有一个空格。例如,Ledger_Period 实际上可能是 200808 。您还可以尝试检查值的长度——我有一个不可见的字符存储在 varchar 字段中的情况。它看起来像一个空字符串,但将其与 '' 进行比较总是错误的。
  • 如果您完整阅读我的问题,您会看到,该字段是float。我对unexpected things happen 部分感兴趣。
  • @dnoeth - 很好的链接(虽然我不擅长数学!)让我看到了指向 Dhahran 失败 http://en.wikipedia.org/wiki/MIM-104_Patriot#Failure_at_Dhahran 的 wiki 链接。让我欣赏我们所做的工作。

标签: sql sql-server except


【解决方案1】:

将值转换为定点类型或字符串,然后重新运行您的代码。第一个查询如下所示:

select Business_Unit_Code, Ledger_Period, cast(Budget_GBP as decimal(18, 2)) as Budget_GBP

有了数字,你看到的并不总是你得到的。所以你看到 32669.19,但它可能真的是 32.669.189999。

【讨论】:

  • Seems to me that the float data type is evil 你之前应该想到的; it's not as if this information is new or anything ;-) 浮点数有其用途,但不是用于货币价值。 '快速修复'是演员,实际修复将所有浮点数更改为货币/小数。在 6:00 左右查看thisIf you understand what you're doing 浮动不是邪恶的。
  • 这是旧版数据库。我无法控制数据类型。不过,我希望向开发人员开枪 :)
【解决方案2】:

您可以定义一个精度并检查该值是否在彼此指定的精度范围内。

declare @accuracy  float = 0.001

select * 
  from      DB_BUDGET1 t1
  full join DB_BUDGET2 t2 
    on  t1.Business_Unit_Code=t2.Business_Unit_Code
    and t1.Ledger_Period     =t2.Ledger_Period
    and t1.Budget_GBP between t2.Budget_GBP-@accuracy  and t2.Budget_GBP+@accuracy 
  where t1.id is null
     or t2.id is null

http://www.sqlfiddle.com/#!3/41da0/2/0

【讨论】:

  • 谢谢。我会试试这个。
猜你喜欢
  • 2011-11-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-07-25
  • 2018-02-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多