簡體   English   中英

選擇查詢,其中一列包含一組數字

[英]Select query where a column contains set of numbers

我必須在具有varchar列的表上寫查詢。 此列中的值可能包含數字作為子字符串

可以說列值是

Data
-----------------------
abc=123/efg=143/ijk=163
abc=123/efg=153/ijk=173

現在我必須查詢表,其中數據包含數字[123,143,163],但不應包含任何其他數字。

如何編寫此選擇查詢?

這看起來像一個非常糟糕的數據庫設計。 如果您對存儲在字符串中的單獨信息感興趣,則不要將字符串存儲,而是將單獨的信息存儲在單獨的列中。 如果可能,請更改此選項,這樣的查詢將變得非常簡單。

但是,暫時可以很容易地找到所描述的記錄,前提是字符串中始終有三個數字,如樣本數據中所示。 在字符串的末尾添加一個斜杠,因此每個數字都有一個前導=和一個尾隨/ 然后使用LIKE查找字符串中的數字。

select *
from mytable
where data || `/` like '%=123/%'
  and data || `/` like '%=143/%'
  and data || `/` like '%=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安裝程序

CREATE TABLE table_name ( data ) AS
SELECT 'abc=123/efg=143/ijk=163' FROM DUAL UNION ALL
SELECT 'abc=123/efg=153/ijk=173' FORM DUAL;

然后,您可以創建一些虛擬列來表示數據:

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
       );

這具有額外的好處,即可以將INTLIST(123, 143, 163) 作為綁定參數 (取決於您使用的客戶端程序和Oracle驅動程序)進行傳遞,以便您可以簡單地更改要過濾的數量和數量對於(值的順序無關緊要)。

此外,如果希望它至少包含這些值,則可以將INTLIST( ... ) =更改為INTLIST( ... ) SUBMULTISET OF

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM