Oracle SQL 在一个字段上加入一个 ID,其中包含一些具有范围的 ID 列表

Oracle SQL Join an ID on a field with a list of IDs some with ranges

首先,这不是我的数据库,我无法更改它:)

这是一个 oracle 数据库

我有一个 table,带有 2 个 ID 字段代码和子代码:

Table1
ID Code Subcode
1  300  010
2  400  050
3  300  060

我有另一个 table 有一个代码范围字段,有一个逗号分隔的代码列表,但有些有一个范围。

Table2
ID CodeRange 
1  300.020,300.040-300.060
2  300.000-300.020,400.010
3  300.180,400.010-400.100,500.010

我希望做一个可以退出的连接:

Table1.ID Table2.ID
1         2
2         3
3         1

注意事项: 第一个数字可以在 IE 300.010-400.190

范围内变化

我的方向是将代码和子代码合并为一个数字,如:

TO_NUMBER(CONCAT(CONCAT(Code, '.'),Subcode))

然后查看将字符串拆分为子字符串(数字)并比较或使用 find_in_set 或类似性质的东西,但我无法到达那里。问题是 CodeRange 有多达 20 个不同的范围,但每个范围的大小都不同。

如有任何帮助,我们将不胜感激。 谢谢

您可以使用分层查询作为

WITH Table2_ AS
(
SELECT ID, REGEXP_SUBSTR(CodeRange,'[^,]+',1,level) AS CodeRange
  FROM Table2
 CONNECT BY level <= REGEXP_COUNT(CodeRange,',') + 1
     AND PRIOR SYS_GUID() IS NOT NULL
     AND PRIOR ID = ID
 ORDER BY ID, level
)
SELECT t1.ID AS t1_ID, t2.ID AS t2_ID
  FROM Table2_ t2
  JOIN Table1 t1
    ON t1.Code BETWEEN TO_NUMBER(REGEXP_SUBSTR(REGEXP_SUBSTR(CodeRange,'[^-]+'),'[^.]+'))
                   AND TO_NUMBER(REGEXP_SUBSTR(REGEXP_SUBSTR(CodeRange,'[^-]+$'),'[^.]+'))
   AND t1.Subcode BETWEEN TO_NUMBER(REGEXP_SUBSTR(REGEXP_SUBSTR(CodeRange,'[^-]+'),'[^.]+$'))
                      AND TO_NUMBER(REGEXP_SUBSTR(REGEXP_SUBSTR(CodeRange,'[^-]+$'),'[^.]+$'))               
 WHERE INSTR(CodeRange,'-')>0  
 ORDER BY t1_ID


 T1_ID  T2_ID
 -----  -----
 1      2
 2      3
 3      1

Demo

哪里

  • 确定了子字符串,其中包含连字符,每个 CodeRange 列,这些列通过使用 REGEXP_SUBSTR() 函数

    用连字符分隔
  • 而不是在 WHERE 条件中使用 数字比较 以防止因 character-wise 比较而获得意外结果。

我对@Barbaros 有类似的方法。通过将 Table2 中的 CSV 拆分为它们自己的行,然后您可以将范围拆分为 beginning/end 范围和显式值作为 beginning/end 的相同值,然后进行数字比较。

WITH
    table1 (ID, Code, Subcode)
    AS
        (SELECT 1, '300', '010' FROM DUAL
         UNION ALL
         SELECT 2, '400', '050' FROM DUAL
         UNION ALL
         SELECT 3, '300', '060' FROM DUAL),
    table2 (ID, CodeRange)
    AS
        (SELECT 1, '300.020,300.040-300.060' FROM DUAL
         UNION ALL
         SELECT 2, '300.000-300.020,400.010' FROM DUAL
         UNION ALL
         SELECT 3, '300.180,400.010-400.100,500.010' FROM DUAL)
  SELECT t1.id AS t1_id, t2.id AS t2_id
    FROM table1 t1
         JOIN
         (SELECT id,
                 REGEXP_SUBSTR (coderange,
                                '[^,]+',
                                1,
                                commas.COLUMN_VALUE)    AS codes
            FROM table2,
                 TABLE (
                     CAST (
                         MULTISET (
                                 SELECT LEVEL
                                   FROM DUAL
                             CONNECT BY LEVEL <= LENGTH (REGEXP_REPLACE (coderange, '[^,]+')) + 1)
                             AS SYS.OdciNumberList)) commas) t2
             ON (TO_NUMBER (t1.code || '.' || t1.subcode) BETWEEN TO_NUMBER (SUBSTR (t2.codes, 1, 7))
                                                              AND TO_NUMBER (
                                                                      NVL (SUBSTR (t2.codes, 9),
                                                                           SUBSTR (t2.codes, 1, 7))))
ORDER BY t1.id;