覆盖Max函数以允许字符串SQL?

问题描述 投票:0回答:2

你好,我觉得这是一个简单的问题,但无法弄清楚。我试图找到与另一列相关的最大数量并将其分组,出现的问题是其中一个值是一个字符串。

Name    Value
Nate    0
Nate    1
Jeff    2
Nate    2
Nate    'Test'

对于数据,我实际上希望'Test'等于1.但是如果我在这里使用MAX()函数,我会得到:

Name    Value
Nate    'Test'
Jeff    2

我只能认为,如果我将'Test'读为1然后使用max函数(我不知道该怎么做)或者可能以某种方式将MAX()重载到我自己的定义中。

感谢您提供任何帮助。

sql oracle
2个回答
2
投票

在字符串列中存储混合数据通常是个坏主意。

您可以使用case表达式将特定字符串转换为固定值:

select max(case when value = 'Test' then '1' else value end) from ...

但是你仍在处理字符串,所以你可能想把它们转换为数字,以防止在'2'之前排序'10',例如:

select max(to_number(case when value = 'Test' then '1' else value end)) from ...

要么

select max(case when value = 'Test' then 1 else to_number(value) end) from ...

使用CTE作为样本数据:

-- CTE for dummy data
with your_table (name, value) as (
  select 'Nate', '0' from dual
  union all select 'Nate', '1' from dual
  union all select 'Jeff', '2' from dual
  union all select 'Nate', '2' from dual
  union all select 'Nate', 'Test' from dual
)
-- actual query
select name,
  max(case when value = 'Test' then 1 else to_number(value) end) as value
from your_table
group by name;

NAME      VALUE
---- ----------
Nate          2
Jeff          2

但是您必须覆盖所有无法显式或隐式转换为数字的值。

如果您想忽略非数字值,或者将它们全部视为相同的固定值,而不是将单个字符串映射到它们自己的数值,那么稍微容易一些。然后你可以编写一个试图转换任何字符串的函数,如果它得到任何异常,则返回null(或其他一些固定值)。

从12cR1开始,您甚至可以使用with a PL/SQL declaration而不是永久性的独立或打包功能,如果这是偶然的事情:

with
  function hack_to_number(string varchar2) return number is
  begin
    return to_number(string);
  exception
    when others then
      return 1;
  end;
select name,
  max(hack_to_number(value)) as value
from your_table
group by name;

NAME      VALUE
---- ----------
Nate          2
Jeff          2

您可能最好回去重新设计数据模型,以通过使用正确的数据类型来防止此类问题。


正如@DrYWit在评论中指出的那样,从12cR2你甚至不需要这样做,因为the to_number() function内置了这个,如果你明确地调用它:

select name,
  max(to_number(value default 1 on conversion error)) as value
from your_table
group by name;

0
投票

这个正则表达式“技巧”怎么样?

SQL> with your_table (name, value) as (
  2    select 'Nate', '0' from dual
  3    union all select 'Nate', '1' from dual
  4    union all select 'Jeff', '2' from dual
  5    union all select 'Nate', '2' from dual
  6    union all select 'Nate', 'Test' from dual
  7  )
  8  select name, max(to_number(value)) mv
  9  from your_table
 10  where regexp_like (value, '^\d+$')
 11  group by name;

NAME         MV
---- ----------
Nate          2
Jeff          2

SQL>
© www.soinside.com 2019 - 2024. All rights reserved.