Oracle使用带有SPLIT的WITH子句连接表[重复]

Posted

技术标签:

【中文标题】Oracle使用带有SPLIT的WITH子句连接表[重复]【英文标题】:Oracle joining tables using WITH clause with SPLIT [duplicate] 【发布时间】:2019-09-10 09:13:43 【问题描述】:

我有这个表没有链接到另一个表,因为它们没有任何相同的列。现在他们想要一个链接两个表格的报告。

但问题是他们唯一的共同列是 WAFER_INFO 列,它有多个用逗号分隔的值,这就是为什么我需要拆分它们以创建多个记录但不同的 WAFER_INFO。

第一个表

select wafer_info 
from bondertab_g3  
where tha_reel_id='TGDT349028H' 
order by insert_dm,tha_reel_id,processlk_ky

上述查询的结果

TGK343067-22,TGK343067-25,TGK343067-24,TGK343067-23

第二张桌子

select hp_part_nr,wafer_id,good_cnt,total_rej_cnt,processlk_ky,toollk_ky,toolnrlk_ky,materiallk_ky 
from sawinsptab 
where wafer_id ='TGK343067-22';

select hp_part_nr,wafer_id,good_cnt,total_rej_cnt,processlk_ky,toollk_ky,toolnrlk_ky,materiallk_ky 
from sawinsptab 
where wafer_id ='TGK343067-25';

select hp_part_nr,wafer_id,good_cnt,total_rej_cnt,processlk_ky,toollk_ky,toolnrlk_ky,materiallk_ky 
from sawinsptab 
where wafer_id ='TGK343067-24';

select hp_part_nr,wafer_id,good_cnt,total_rej_cnt,processlk_ky,toollk_ky,toolnrlk_ky,materiallk_ky 
from sawinsptab 
where wafer_id ='TGK343067-23';

基本上都在第一个表中

我已经了解如何使用此代码拆分所有这些记录

With DATA AS (
  select tha_reel_id, wafer_info str 
  from bondertab_g3
  where tha_reel_id='TGDT349028H'
)
SELECT A.tha_reel_id, trim(regexp_substr(A.str, '[^,]+', 1, LEVEL)) WAFERID FROM DATA A
CONNECT BY instr(str, ',', 1, LEVEL - 1) > 0

现在我的问题是,当唯一相同的列是 WAFERID 时,如何连接上面的查询并将其连接到第二个表

【问题讨论】:

如果您需要在加入之前拆分字符串,您有一个设计错误并且必须规范化您的数据。服务器不能在这些列上使用任何索引,并且必须扫描整个表以查找匹配项。即使是少量数据,这也会非常变慢 与示例 I/O 数据共享表结构,这将有所帮助 您的拆分函数将生成重复行,随着输入行数和分隔项数的增加,重复行的频率将呈指数增长(因为分层查询无法与特定父行相关,因此将与所有父行)。 【参考方案1】:

查找sawinsptab.wafer_id(包含在逗号分隔符中)是bondertab_g3.wafer_info(包含在逗号分隔符中)的子字符串:

select hp_part_nr,
       wafer_id,
       good_cnt,
       total_rej_cnt,
       processlk_ky,
       toollk_ky,
       toolnrlk_ky,
       materiallk_ky 
from   sawinsptab s
where  EXISTS (
  select 1
  from   bondertab_g3 b
  where  b.tha_reel_id='TGDT349028H'
  and    ','||b.wafer_info||',' LIKE '%,'||s.wafer_id||',%'
);

select s.hp_part_nr,
       s.wafer_id,
       s.good_cnt,
       s.total_rej_cnt,
       s.processlk_ky,
       s.toollk_ky,
       s.toolnrlk_ky,
       s.materiallk_ky,
       b.other_column
from   sawinsptab s
       INNER JOIN bondertab_g3 b
       ON ( ','||b.wafer_info||',' LIKE '%,'||s.wafer_id||',%' )
where  b.tha_reel_id='TGDT349028H';

或者,如果您需要在wafer_id 上使用索引并想要拆分分隔字符串,则可以使用递归子查询因式分解子句和简单的字符串函数(而不是慢速正则表达式):

select hp_part_nr,
       wafer_id,
       good_cnt,
       total_rej_cnt,
       processlk_ky,
       toollk_ky,
       toolnrlk_ky,
       materiallk_ky 
from   sawinsptab s
where  wafer_id IN (
  WITH delimiter_bounds ( wafer_info, startidx, endidx ) AS (
    SELECT wafer_info,
           1,
           INSTR( wafer_info, ',', 1 )
    FROM   bondertab_g3
    WHERE  tha_reel_id='TGDT349028H'
  UNION ALL
    SELECT wafer_info,
           endidx + 1,
           INSTR( wafer_info, ',', endidx + 1 )
    FROM   delimiter_bounds
    WHERE  endidx > 0
  )
  SELECT CASE
         WHEN endidx = 0
         THEN SUBSTR( wafer_info, startidx )
         ELSE SUBSTR( wafer_info, startidx, endidx - startidx )
         END
  from   delimiter_bounds
);

WITH delimiter_bounds ( wafer_info, other_column, startidx, endidx ) AS (
  SELECT wafer_info,
         other_column,
         1,
         INSTR( wafer_info, ',', 1 )
  FROM   bondertab_g3
  WHERE  tha_reel_id='TGDT349028H'
UNION ALL
  SELECT wafer_info,
         other_column,
         endidx + 1,
         INSTR( wafer_info, ',', endidx + 1 )
  FROM   delimiter_bounds
  WHERE  endidx > 0
)
select s.hp_part_nr,
       s.wafer_id,
       s.good_cnt,
       s.total_rej_cnt,
       s.processlk_ky,
       s.toollk_ky,
       s.toolnrlk_ky,
       s.materiallk_ky,
       b.other_column
from   sawinsptab s
       INNER JOIN (
         SELECT CASE
                WHEN endidx = 0
                THEN SUBSTR( wafer_info, startidx )
                ELSE SUBSTR( wafer_info, startidx, endidx - startidx )
                END AS wafer_id,
                other_column
         FROM   delimiter_bounds
       ) b
       ON ( s.wafer_id = b.wafer_id )

【讨论】:

谢谢你,但如果我还需要选择中包含的第二个表bondertab_g3 上的数据怎么办?我试过添加它,但它没有出现。 @Gene 更新为INNER JOIN【参考方案2】:

您可以将第一个查询更改为 CTE,然后直接在您的查询中使用它:

with data as (
      select tha_reel_id, wafer_info str 
      from bondertab_g3
      where tha_reel_id = 'TGDT349028H'
     ),
     wafers as (
      select d.tha_reel_id, trim(regexp_substr(d.str, '[^,]+', 1, LEVEL)) as waferid 
      from data d
      connect by instr(str, ',', 1, LEVEL - 1) > 0
     )
select s.*
from sawinsptab s 
where wafer_id in (select w.waferid from wafers);

【讨论】:

以上是关于Oracle使用带有SPLIT的WITH子句连接表[重复]的主要内容,如果未能解决你的问题,请参考以下文章

如何使用带有 WITH 子句的 INSERT 语句?

WITH 子句可以在不使用 Select 语句的情况下具有硬编码值吗?

如何使用带有过滤器 where 子句的 oracle 外连接

Oracle12c中功能及性能新特点之with子句的增强

MySQL "WITH" 子句

2 带有 WHERE 子句的表连接