2

因此,我有一列数据,使用前面的示例,体温,它存储为 varchar,因此没有记录被拒绝,但是,它包含数字数据。

向我发送数据的人使用的系统不够完善,所以我有一些不正确的数据。我需要做的是编写一个 SQL 查询来查找高于或低于某个值的有效值。

例如,所有超过 104 的温度,应指示极端情况或错误。

我试过了:

select count(1), result_num from VITALS where test_cd is 'TEMP' and cast(result_num as integer) > 104 group by result_num;

这返回了一个无效数字错误,所以我认为我在某些行上有无法转换为整数的字符,我发现记录有负值(数字前的“-”)和一些说“NULL”的记录,所以我修改了我要阅读的查询:

select count(1), result_num from VITALS where test_cd is 'TEMP' **and result_num not like '%-%' and result_num not like '%NULL%'** and cast(result_num as integer) > 104 group by result_num;

...它仍然返回一个无效的数字错误。我已经三次检查了我的 RESULT_NUM 字段中的数据,这些是唯一的字符响应。

所有其他响应,无论是否合法临时,都是数字,除了小数之外没有其他字符。

我是否需要在括号或其他内容中链接“不喜欢”语句?

这可能是一个简单的答案,但它让我发疯。

4

3 回答 3

1

这对我有用。这本质上是@Alex 对子查询提出的建议。希望它适用于您的源数据:

SELECT count(*), result_num
FROM
(
  SELECT
  test_cd,
  CASE WHEN REGEXP_LIKE(result_num,'^-?[0-9]*\.?[0-9]*$')
    THEN result_num - 0
    ELSE NULL
  END result_num
  FROM vitals
) 
WHERE test_cd='TEMP'
  AND result_num > 104
GROUP BY result_num;

另一个不同的想法:如果您使用的是 Oracle 11g,并且您有能力建议/进行表结构更改,我可能会喜欢在表中添加一个虚拟列(即计算列)来计算净化的表的想法数值。行为类似于视图,但使用虚拟列有两个很大的优势:(1) 没有其他对象,仍然是一个对象,vitals表,以及 (2) 您可以在虚拟列上建立索引(逻辑上与功能指标)。

如果您不在 11g 上,或者如果虚拟列听起来像炼金术,另一种方法是制作一个普通的旧列来保存经过清理的值并让触发器在插入/更新时计算其值。

于 2014-06-19T06:38:30.150 回答
1

您可以使用此答案提供的函数或正则表达式过滤掉非数字值- 这可能需要一些调整:

select count(1), result_num
from vitals
where test_cd = 'TEMP'
and regexp_like(result_num, '^[-]?[0-9]*[\.]?[0-9]*$')
and cast(result_num as integer) > 104
group by result_num;

SQL 小提琴

这将排除大多数非数字(也许全部,但我没有那么自信 - 正则表达式不是一个强大的领域),尽管贾斯汀的函数可能更安全。

但是,仍然不能保证在转换之前会应用过滤器功能。如果这仍然出错,那么您可以使用子查询过滤掉非数字值,然后检查剩余的实际值;但是您可能需要添加一个提示来阻止 Oracle 取消嵌套子查询并更改您的评估顺序。

另一种方法是 Justin 函数的变体,它返回实际数字:

CREATE OR REPLACE FUNCTION safe_number( p_str IN VARCHAR2 )
  RETURN NUMBER DETERMINISTIC PARALLEL_ENABLE
IS
  l_num NUMBER;
BEGIN
  l_num := to_number( p_str );
  RETURN l_num;
EXCEPTION
  WHEN value_error THEN
    RETURN null;
END safe_number;
/

然后您的查询可以使用它:

select count(1), result_num
from vitals
where test_cd = 'TEMP'
and safe_number(result_num) > 104
group by result_num;

SQL 小提琴

于 2014-06-18T22:53:24.410 回答
0

编辑:如果您使用的版本高于 Oracle 10g,则可以使用正则表达式在 result_num 中仅查找数字字符。由于要过滤掉小数和负数,因此可以简单地查找字符 0-9,如下所示:

select result_num , count(1) as cnt_result_num
from VITALS 
where test_cd = 'TEMP' 
and result_num IS NOT NULL
and regexp_like(result_num, '^[0-9]*$')
and cast(result_num as integer) > 104 
group by result_num;

SQL Fiddle

参考

Oracle 数据库 SQL 参考上的 REGEXP_LIKE

于 2014-06-18T17:02:03.053 回答