Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/oracle/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 选择列包含一组数字的查询_Sql_Oracle - Fatal编程技术网

Sql 选择列包含一组数字的查询

Sql 选择列包含一组数字的查询,sql,oracle,Sql,Oracle,我必须在一个有varchar列的表上写一个查询。此列中的值可以有一个数字作为子字符串 假设列值为 Data ----------------------- abc=123/efg=143/ijk=163 abc=123/efg=153/ijk=173 现在我必须查询表,其中数据包含数字[123143163],但不应包含任何其他数字 如何编写此选择查询?这看起来是一个非常糟糕的数据库设计。如果您对存储在字符串中的单独信息感兴趣,那么不要存储字符串,而是将单独的信息存储在单独的列中。如果可能的话,

我必须在一个有varchar列的表上写一个查询。此列中的值可以有一个数字作为子字符串

假设列值为

Data
-----------------------
abc=123/efg=143/ijk=163
abc=123/efg=153/ijk=173
现在我必须查询表,其中数据包含数字[123143163],但不应包含任何其他数字


如何编写此选择查询?

这看起来是一个非常糟糕的数据库设计。如果您对存储在字符串中的单独信息感兴趣,那么不要存储字符串,而是将单独的信息存储在单独的列中。如果可能的话,更改此选项,这样的查询将变得非常简单

但是,目前很容易找到所描述的记录,前提是字符串中始终有三个数字,如示例数据中所示。在字符串末尾添加斜杠,使每个数字都有一个前导=和一个尾随/。然后用LIKE查找字符串中的数字

如果这三个数字在字符串中,则所有数字都匹配。因此,没有其他号码不匹配

如果字符串中可以有更多的数字,但没有重复的数字,则计算等号以确定字符串中有多少数字:

select *
from mytable
where data || '/' like '%=123/%'
  and data || '/' like '%=143/%'
  and data || '/' like '%=163/%'
  and regexp_count(data, '=') = 3;
select *
from mytable
where regexp_count(data, '=') >= 3
  and regexp_count(data, '=') =
      regexp_count(data || '/', '=123/') +
      regexp_count(data || '/', '=143/') +
      regexp_count(data || '/', '=163/');
下面是一个接受字符串中重复数字的查询:

select *
from mytable
where data || '/' like '%=123/%'
  and data || '/' like '%=143/%'
  and data || '/' like '%=163/%'
  and regexp_count(data, '=') = 3;
select *
from mytable
where regexp_count(data, '=') >= 3
  and regexp_count(data, '=') =
      regexp_count(data || '/', '=123/') +
      regexp_count(data || '/', '=143/') +
      regexp_count(data || '/', '=163/');

这看起来像是一个非常糟糕的数据库设计。如果您对存储在字符串中的单独信息感兴趣,那么不要存储字符串,而是将单独的信息存储在单独的列中。如果可能的话,更改此选项,这样的查询将变得非常简单

但是,目前很容易找到所描述的记录,前提是字符串中始终有三个数字,如示例数据中所示。在字符串末尾添加斜杠,使每个数字都有一个前导=和一个尾随/。然后用LIKE查找字符串中的数字

如果这三个数字在字符串中,则所有数字都匹配。因此,没有其他号码不匹配

如果字符串中可以有更多的数字,但没有重复的数字,则计算等号以确定字符串中有多少数字:

select *
from mytable
where data || '/' like '%=123/%'
  and data || '/' like '%=143/%'
  and data || '/' like '%=163/%'
  and regexp_count(data, '=') = 3;
select *
from mytable
where regexp_count(data, '=') >= 3
  and regexp_count(data, '=') =
      regexp_count(data || '/', '=123/') +
      regexp_count(data || '/', '=143/') +
      regexp_count(data || '/', '=163/');
下面是一个接受字符串中重复数字的查询:

select *
from mytable
where data || '/' like '%=123/%'
  and data || '/' like '%=143/%'
  and data || '/' like '%=163/%'
  and regexp_count(data, '=') = 3;
select *
from mytable
where regexp_count(data, '=') >= 3
  and regexp_count(data, '=') =
      regexp_count(data || '/', '=123/') +
      regexp_count(data || '/', '=143/') +
      regexp_count(data || '/', '=163/');
Oracle安装程序:

然后,您可以创建一些虚拟列来表示数据:

ALTER TABLE table_name ADD abc GENERATED ALWAYS AS (
  TO_NUMBER( REGEXP_SUBSTR( data, '(^|/)abc=(\d+)(/|$)', 1, 1, NULL, 2 ) )
) VIRTUAL;
ALTER TABLE table_name ADD efg GENERATED ALWAYS AS (
  TO_NUMBER( REGEXP_SUBSTR( data, '(^|/)efg=(\d+)(/|$)', 1, 1, NULL, 2 ) )
) VIRTUAL;
ALTER TABLE table_name ADD ijk GENERATED ALWAYS AS (
  TO_NUMBER( REGEXP_SUBSTR( data, '(^|/)ijk=(\d+)(/|$)', 1, 1, NULL, 2 ) )
) VIRTUAL;
如果需要,可以添加适当的索引:

CREATE INDEX table_name__abc_efg_ijk__idx ON table_name( abc, efg, ijk );
查询:

然后,如果您只需要这三把钥匙,您可以:

SELECT abc, efg, ijk
FROM   table_name
WHERE  abc = 123
AND    efg = 143
AND    ijk = 163;
但是,如果您可以获得三个以上的键并希望忽略其他值,则可以执行以下操作:

CREATE TYPE intlist AS TABLE OF INT;
/

SELECT *
FROM   table_name
WHERE  INTLIST( 143, 123, 163 )
       =
       CAST(
         MULTISET(
           SELECT TO_NUMBER(
                    REGEXP_SUBSTR(
                      t.data,
                      '[^/=]+=(\d+)(/|$)',
                      1,
                      LEVEL,
                      NULL,
                      1
                    )
                  )
           FROM   DUAL
           CONNECT BY LEVEL <= REGEXP_COUNT( t.data, '[^/=]+=(\d+)(/|$)' )
         )
         AS INTLIST
       );
这还有一个额外的好处,INTLIST123、143、163可能取决于您使用的客户端程序和Oracle驱动程序,因此您可以简单地更改要筛选的数量和数字,并且值的顺序无关紧要

此外,如果希望它至少包含这些值,则可以更改INTLIST…=要列出。。。Oracle设置的子多集:

然后,您可以创建一些虚拟列来表示数据:

ALTER TABLE table_name ADD abc GENERATED ALWAYS AS (
  TO_NUMBER( REGEXP_SUBSTR( data, '(^|/)abc=(\d+)(/|$)', 1, 1, NULL, 2 ) )
) VIRTUAL;
ALTER TABLE table_name ADD efg GENERATED ALWAYS AS (
  TO_NUMBER( REGEXP_SUBSTR( data, '(^|/)efg=(\d+)(/|$)', 1, 1, NULL, 2 ) )
) VIRTUAL;
ALTER TABLE table_name ADD ijk GENERATED ALWAYS AS (
  TO_NUMBER( REGEXP_SUBSTR( data, '(^|/)ijk=(\d+)(/|$)', 1, 1, NULL, 2 ) )
) VIRTUAL;
如果需要,可以添加适当的索引:

CREATE INDEX table_name__abc_efg_ijk__idx ON table_name( abc, efg, ijk );
查询:

然后,如果您只需要这三把钥匙,您可以:

SELECT abc, efg, ijk
FROM   table_name
WHERE  abc = 123
AND    efg = 143
AND    ijk = 163;
但是,如果您可以获得三个以上的键并希望忽略其他值,则可以执行以下操作:

CREATE TYPE intlist AS TABLE OF INT;
/

SELECT *
FROM   table_name
WHERE  INTLIST( 143, 123, 163 )
       =
       CAST(
         MULTISET(
           SELECT TO_NUMBER(
                    REGEXP_SUBSTR(
                      t.data,
                      '[^/=]+=(\d+)(/|$)',
                      1,
                      LEVEL,
                      NULL,
                      1
                    )
                  )
           FROM   DUAL
           CONNECT BY LEVEL <= REGEXP_COUNT( t.data, '[^/=]+=(\d+)(/|$)' )
         )
         AS INTLIST
       );
这还有一个额外的好处,INTLIST123、143、163可能取决于您使用的客户端程序和Oracle驱动程序,因此您可以简单地更改要筛选的数量和数字,并且值的顺序无关紧要

此外,如果希望它至少包含这些值,则可以更改INTLIST…=要列出。。。子多重集