查询表使用不同的变量列表

时间:2017-02-15 10:55:21

标签: sql sql-server oracle

我打电话给网络服务,我得到一个代码列表:A,B,C,D,E,F等。

在我的问题中,我得到A,B,C。

有一个表格,您可以使用上述代码创建集合,对于每个集合,您可以添加特定消息,以便最终用户可以理解代码。 例如,A表示" ok",B表示"您可以登录" 因此,对于集合A,B,消息可以是"您可以登录"。 代码集保存在一列(代码)中。

在我的问题中,我使用以下查询查询表:

Select setid, codes, messagedescr from table1 where setid = (select max(setid) from  table1 
                        And codes Like '%A%'  
                        And codes Like '%B%'  
                        And codes Like '%C%');

此查询找到一行,但错误,列"代码"包含以下代码:A,B,C,D。

例如:

setid   codes       messagedescr
1       A, B, C, D  You can login
2       B, C, D     You can login for one day
3       A, C, E     You can login but update your profile
4       B, C, E, F  You cannot login

我不知道网络服务中代码的顺序,我不知道代码是如何保存在表格中的,所以我不得不做一些没有订单的东西,这就是我使用Likes的原因。 共有25个代码:A,B,C等

如何修复查询以便找到正确的消息?

谢谢!

更新 谢谢大家的答案,特别是那些有额外工作的更详细的答案,比如创建表格。 该表可能有10-20行。 一种情况是为代码创建另一个表并将其与set id连接。或者另一种情况是计算服务中代码的长度,看它们是否与表中的长度匹配。

2 个答案:

答案 0 :(得分:1)

如果我理解你的需要,这可能是一种方式。

假设你有一张这样的表:

create table yourTable(setid, codes, messagedescr) as ( 
  select 1,       'A, B, C, D',  'You can login' from dual union all
  select 2,       'B, C, D'   ,  'You can login for one day' from dual union all
  select 3,       'A, C, E'   ,  'You can login but update your profile' from dual union all
  select 4,       'B, C, E, F',  'You cannot login' from dual
).

这可能是一种方式:

with inputData(codes) as (
    select listagg(trim (regexp_substr(input_codes, '[^,]+', 1, level))) within group ( order by trim (regexp_substr(input_codes, '[^,]+', 1, level)))
    from ( select 'A, D, C, B' as input_codes from dual )  /* the input string */
    CONNECT BY instr(input_codes, ',', 1, level - 1) > 0
)    
select *
from inputData 
    inner join (
                select listagg(trim (regexp_substr(codes, '[^,]+', 1, level)))
                         within group ( order by trim (regexp_substr(codes, '[^,]+', 1, level))) as codes,
                        messagedescr
                from yourTable  
                CONNECT BY instr(codes, ',', 1, level - 1) > 0
                  and prior setId = setId
                  and prior sys_guid() is not null
                group by setId, messagedescr
               )
      using (codes)

这里的想法是将输入字符串拆分为多行,然后按字母顺序聚合生成的行,然后对表中的值应用相同的顺序,然后检查有序字符串是否相等。

此部分用于分割,排序和聚合输入值,以便结果是有序字符串:

select listagg(trim (regexp_substr(input_codes, '[^,]+', 1, level))) within group ( order by trim (regexp_substr(input_codes, '[^,]+', 1, level)))
    from ( select 'A, D, C, B' as input_codes from dual )  /* the input string */
    CONNECT BY instr(input_codes, ',', 1, level - 1) > 0

给出:

ABCD

这部分用于在你的桌子上做同样的事情:

select listagg(trim (regexp_substr(codes, '[^,]+', 1, level)))
         within group ( order by trim (regexp_substr(codes, '[^,]+', 1, level))) as codes,
        messagedescr
from yourTable  
CONNECT BY instr(codes, ',', 1, level - 1) > 0
  and prior setId = setId
  and prior sys_guid() is not null
group by setId, messagedescr  

给出:

CODES      MESSAGEDESCR
---------- -------------------------------------
ABCD       You can login
BCD        You can login for one day
ACE        You can login but update your profile
BCEF       You cannot login

这些部分结果之间的连接非常简单,只需检查表中是否存在与(有序)输入字符串对应的值(有序)。

答案 1 :(得分:1)

Oracle安装程序

从一个简单的split a delimited string函数开始到集合中:

CREATE OR REPLACE TYPE stringlist AS TABLE OF VARCHAR2(20)
/

CREATE OR REPLACE FUNCTION split_String(
  i_str    IN  VARCHAR2,
  i_delim  IN  VARCHAR2 DEFAULT ','
) RETURN stringlist DETERMINISTIC
AS
  p_result       stringlist := stringlist();
  p_start        NUMBER(5) := 1;
  p_end          NUMBER(5);
  c_len CONSTANT NUMBER(5) := LENGTH( i_str );
  c_ld  CONSTANT NUMBER(5) := LENGTH( i_delim );
BEGIN
  IF c_len > 0 THEN
    p_end := INSTR( i_str, i_delim, p_start );
    WHILE p_end > 0 LOOP
      p_result.EXTEND;
      p_result( p_result.COUNT ) := SUBSTR( i_str, p_start, p_end - p_start );
      p_start := p_end + c_ld;
      p_end := INSTR( i_str, i_delim, p_start );
    END LOOP;
    IF p_start <= c_len + 1 THEN
      p_result.EXTEND;
      p_result( p_result.COUNT ) := SUBSTR( i_str, p_start, c_len - p_start + 1 );
    END IF;
  END IF;
  RETURN p_result;
END;
/

以及一些示例数据:

CREATE TABLE your_table( setid, codes, messagedescr ) 
  SELECT 1, 'A,B,C,D', 'You can login' FROM DUAL UNION ALL
  SELECT 2, 'B,C,D',   'You can login for one day' FROM DUAL UNION ALL
  SELECT 3, 'A,C,E',   'You can login but update your profile' FROM DUAL UNION ALL
  SELECT 4, 'B,C,E,F', 'You cannot login' FROM DUAL;

然后你可以做(​​以任何顺序传递输入C,A,B - 作为绑定参数:your_code):

SELECT *
FROM   (
  SELECT *
  FROM   your_table
  WHERE  split_string( codes ) SUBMULTISET OF split_String( :your_code )
  ORDER BY setid DESC
)
WHERE ROWNUM = 1;

,它将输出具有最高匹配代码集的行。

注意:上面的示例假设您需要将表中的所有代码与输入字符串中的代码进行匹配。如果您只需要匹配至少一个,那么您可以使用:

WHERE split_string( codes ) MULTISET INTERSECT split_String( :your_code ) IS NOT EMPTY