1

Oracleデータベーステーブルで、特定のロット番号の結果を見つける必要があります。ロット番号が保存されるフィールドは、「1-3,5,10-15,20」のような文字列です(この文字列内の番号はソートされています)

これを行う方法はありますか?

上記の例では、次のロット番号の結果が見つかります。

1,2,3,5,10,11,12,13,14,15,20

アプリケーションでそれを行う方法はないので、データベース内で行う必要があります。

次のようなもの: "SELECT * FROM products WHERE lot = 2"

4

4 に答える 4

7

REGEXP_SUBSTR関数と階層クエリを使用して、これをすべて SQL で行うことができます。

with list_of_ids as (
select regexp_substr(a, '[[:digit:]]+',1, 1) as lot1
     , nvl( regexp_substr(a, '(-)([[:digit:]]+)',1, 1, 'i', '2')
          , regexp_substr(a, '[[:digit:]]+',1, 1)) as lot2
  from (select regexp_substr('1-3,5,10-15,20' , '[^,]+', 1, level) as a
          from dual
       connect by regexp_substr('1-3,5,10-15,20' , '[^,]+', 1, level) is not null
               )
       )
select a.*
  from products a
  join list_of_ids b
    on a.lot between b.lot1 and b.lot2

ただし、データベースを適切に正規化することが最善の方法であることを強調しなければなりません。このソリューションはうまくスケーリングできない可能性があり、非常に不必要な量の作業を行います。

それはこのように動作します:

最初にコンマでデータを分割します。

SQL>  select regexp_substr('1-3,5,10-15,20', '[^,]+', 1, level) as a
  2     from dual
  3  connect by regexp_substr('1-3,5,10-15,20', '[^,]+', 1, level) is not null
  4          ;

A
--------------
1-3
5
10-15
20

次に、それをハイフンで分割して、BETWEEN で使用する最小ロットと最大ロットを提供してから、最終的にテーブルに結合します。NVL は、常に最大値が存在することを保証するために存在します。

SQL> select regexp_substr(a, '[[:digit:]]+',1, 1) as lot1
  2       , nvl( regexp_substr(a, '(-)([[:digit:]]+)',1, 1, 'i', '2')
  3             , regexp_substr(a, '[[:digit:]]+',1, 1)) as lot2
  4    from (select regexp_substr('1-3,5,10-15,20' , '[^,]+', 1, level) as a
  5            from dual
  6         connect by regexp_substr('1-3,5,10-15,20' , '[^,]+', 1, level) is not null
  7                 )
  8         ;

LOT1           LOT2
-------------- --------------
1              3
5              5
10             15
20             20

SQL>

これは、完全なクエリを使用した実際のSQL Fiddleです。

于 2013-01-22T14:03:06.967 に答える
3

これはPIPELINED FUNCTIONを使用したソリューションです。

create type array_number
    as table of number
/ 

create or replace function x_tbl(a varchar2) return array_number pipelined  as
token varchar2(10);
str varchar2(1000):=a;
k number;
should_exit boolean;
begin
should_exit := false;
loop
    if instr(str,',') > 0 then 
        token:=substr(str,1,instr(str,',')-1);
    else 
        token := str;
        should_exit:=true;
    end if;
    if instr(token,'-') > 0 then 
        k:=to_number(substr(token, 1, instr(token,'-')-1)) ;
        loop
            pipe row(k);
            k:=k+1;
            exit when k>to_number(substr(token, instr(token,'-')+1)) ;
        end loop;
    else pipe row(token);
    end if;
    --dbms_output.put_line(token);
    --dbms_output.put_line(instr(str,','));
    str:=substr(str, instr(str,',')+1);
    exit when should_exit;
end loop;
end;
/

クエリ:

select * from table(x_tbl('22-27,33,444-448'));

結果:

22
23
24
25
26
27
33
444
445
446
447
448

だからあなたはできる:

 select 1 from dual where 23 in (select * from  table(x_tbl('22-27,33,444-448')));
于 2013-01-22T14:21:10.567 に答える
-1

これは T-SQL ですが、移植は難しくありません。

DECLARE @ranges NVARCHAR(MAX);
DECLARE @number INT;

SET @ranges = N'1-3,5,10-15,20';
SET @number = 13;

DECLARE @found BIT;
DECLARE @commaIndex INT;
DECLARE @dashIndex INT;
DECLARE @range NVARCHAR(MAX);
DECLARE @rangeStart INT;
DECLARE @rangeEnd INT;

SET @found = 0;

SET @commaIndex = CHARINDEX(',', @ranges);

WHILE (@commaIndex > 0) BEGIN

  SET @range = SUBSTRING(@ranges, 1, @commaIndex - 1);

  SET @dashIndex = CHARINDEX('-', @range);

  IF (@dashIndex > 0) BEGIN

     SET @rangeStart = CAST(SUBSTRING(@range, 1, @dashIndex - 1) AS INT);
     SET @rangeEnd = CAST(SUBSTRING(@range, @dashIndex + 1, LEN(@range) - @dashIndex) AS INT);

  END ELSE BEGIN

     SET @rangeStart = CAST(@range AS INT);
     SET @rangeEnd = @rangeStart;

  END;

  IF ((@rangeStart <= @number) AND (@number <= @rangeEnd)) BEGIN

    SET @found = 1;

    BREAK;

  END;

  SET @ranges = SUBSTRING(@ranges, @commaIndex + 1, LEN(@ranges) - @commaIndex);
  SET @commaIndex = CHARINDEX(',', @ranges);

END;

IF (@found = 1) BEGIN

    PRINT N'Contained.';

END ELSE BEGIN

    PRINT N'Not contained.';

END;
于 2013-01-22T13:56:16.187 に答える
-4

これは、SQL のみを使用する必要がある場合の最も簡単なソリューションです。PL/SQL を使用している場合は、さらに多くのソリューションがあります。しかし、これが最も効率的でシンプルな場合があります。ハードコードされた数字の代わりに、もちろん文字列があります:

SELECT * FROM products WHERE lot IN (Replace('1-3,5,10-15,20', '-', ',') )
/

必要に応じて、文字列内のより多くの文字を削除/置換する方法があります。上記の例では、「-」を「,」のみに置き換えています...

問題は、これを取得する方法でした:

"SELECT * FROM products WHERE lot = 2..."

これではない:

1-3,
2,
4
...

質問/例を明確に述べてください。

于 2013-01-22T13:43:30.403 に答える