与ANY()

时间:2019-08-07 16:39:01

标签: sql postgresql any

我有一个3列的表格,其中一个是长度不均匀的文本数组(模块)。我想根据与确定的文本模式/短语匹配的模块数组中元素的存在来创建派生表。元素名称也可以有所不同,尽管它会有一个通用短语。 下面给出了一个无效的示例:

    select machine_id, jobid, 
    case
    when '%charmm%' LIKE ANY(modules) then 'CHARMM'
    when '%gaussian%' LIKE ANY(modules) then 'GAUSSIAN'
    else 'OTHERS'
    end as package, modules
    from jobapps limit 50;

在这种情况下,可能有多个高斯模块名称:gaussian / 16b01,gaussian / 09e01。但是我想重点关注短语“高斯”,并创建一个新列,其中所有与文本模式“高斯”匹配的条目都将标记为“高斯”。

这就是为什么我想使用'%gaussian%'象ANY(模块)的原因,这是行不通的。

我可以使用:'gaussian / 09e01'像ANY(modules),但是在那种情况下,我必须写所有可能的值,并且如果用户创建了一个新的Gaussian模块,那么该数据将丢失。

有什么办法可以纠正上述问题?还是有更好的方法实现目标?

    select machine_id, jobid, 
    case
    when '%charmm%' LIKE ANY(modules) then 'CHARMM'
    when '%gaussian%' LIKE ANY(modules) then 'GAUSSIAN'
    else 'OTHERS'
    end as package, modules
    from jobapps limit 50;

我想得到类似的东西:

    machine_id | jobid  | package  |         modules          
    ------------+--------+----------+--------------------------
    6 | 1884 | CHARMM   | {charmm}
    2 | 2305 | CHARMM   | {charmm}
    6 | 786  | GAUSSIAN | {gaussian/09e1}
    7 | 1956 | CHARMM   | {charmm}
    3 | 72037| NAMD     | {namd,intel/2018}

1 个答案:

答案 0 :(得分:0)

LIKE运算符要求模式在右边,而ANY()表达式将始终使用数组成员作为正确的操作数,因此我认为没有简单的出路。

您可以创建自己的“反向类似”运算符,其操作数取反:

create function reverse_like(text,text) returns boolean as
'select $2 like $1'
language sql immutable;

create operator <~~ (
  function = reverse_like,
  leftarg = text,
  rightarg = text
);

...然后使用以下命令查询您的数组:

case
when '%charmm%' <~~ ANY(modules) then 'CHARMM'
when '%gaussian%' <~~ ANY(modules) then 'GAUSSIAN'

如果您不想仅为该查询创建新的运算符,我认为您将需要做很长的路要走,方法是取消嵌套数组并检查子查询中的内容:

case
when exists (select 1 from unnest(modules) u(v) where v like '%charmm%') then 'CHARMM'
when exists (select 1 from unnest(modules) u(v) where v like '%gaussian%') then 'GAUSSIAN'

...或者:

case
when (select bool_or(v like '%charmm%') from unnest(modules) u(v)) then 'CHARMM'
when (select bool_or(v like '%gaussian%') from unnest(modules) u(v)) then 'GAUSSIAN'