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
哪里
确定了子字符串,其中包含连字符,每个
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;
首先,这不是我的数据库,我无法更改它:)
这是一个 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
哪里
确定了子字符串,其中包含连字符,每个
用连字符分隔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;