【问题标题】:Oracle SQL Join an ID on a field with a list of IDs some with rangesOracle SQL 在一个字段上加入一个 ID,其中包含一个 ID 列表,其中一些具有范围
【发布时间】:2020-10-29 17:54:36
【问题描述】:

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

这是一个oracle数据库

我有一个包含 2 个 ID 字段代码和子代码的表格:

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

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

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 个不同的范围,但每个范围的大小各不相同。

任何帮助将不胜感激。 谢谢

【问题讨论】:

    标签: sql regex oracle substr


    【解决方案1】:

    我对@Barbaros 有类似的方法。通过将 Table2 中的 CSV 拆分为各自的行,您可以将范围拆分为开始/结束范围,并将显式值拆分为相同的开始/结束值,然后进行数值比较。

    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;
    

    【讨论】:

    • 这个似乎工作并产生比另一个多 1000 条记录(见下面的评论)但是它有点超出我的技能,因为这是一个多连接查询提取一个代码和一个子代码,我无法弄清楚如何加入它以拉出代码范围
    • 您能否举一个您正在尝试查找的代码/子代码的示例,我可以向您展示如何将其构建到查询中?
    • @Pearl,由于您引用了 JOIN 语法,因此我已将查询从 Oracle 连接语法转换为 ANSII 连接语法,希望能更容易理解查询。
    • 我能够加入它。我还没有 QC,但它看起来不错,谢谢!
    【解决方案2】:

    您可以将分层查询用作

    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 条件中使用数字比较而不是串联,以防止因字符比较而导致意外结果。

    【讨论】:

    • 这只会匹配范围内的代码/子代码,而不是明确指定的代码/子代码。例如,如果 Table1 有一行 4 500 010,它将无法正确匹配到 Table2 中的 ID 3
    • 好吧,我最近也意识到当前值没有问题,但是需要与意外值进行数字比较 @EJEgyed ,同时我正在修复它。无论如何,谢谢。
    • 我更喜欢这个,因为它是一个连接,但是这个产生的记录比 EJ Egyed 的版本少 1000 条。也许是因为我没有说明 table1 代码可以在多个 table 2 条目中?谢谢
    猜你喜欢
    • 2016-07-26
    • 2018-11-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多