【问题标题】:Insert valid records from SP into valid table and Invalid records into Invalid SP将 SP 中的有效记录插入到有效表中,将无效记录插入到 Invalid SP 中
【发布时间】:2020-07-19 13:25:20
【问题描述】:

我有两个存储过程,它们过滤表上的记录并给出结果。以下是存储过程。

SELECT distinct  TO_CHAR(sp.RJ_SPAN_ID) AS SPAN_ID
               , TO_CHAR(sp.RJ_MAINTENANCE_ZONE_CODE) AS MAINT_ZONE_CODE
from  APP_FTTX.span@SAT sp
INNER JOIN APP_FTTX.transmedia@SAT tm  -- transmedia added
on sp.RJ_SPAN_ID = tm.RJ_SPAN_ID
WHERE length(sp.RJ_SPAN_ID) = length(tm.RJ_SPAN_ID)
and sp.RJ_MAINTENANCE_ZONE_CODE = tm.RJ_MAINTENANCE_ZONE_CODE
and sp.INVENTORY_STATUS_CODE = tm.INVENTORY_STATUS_CODE
AND LENGTH(sp.RJ_SPAN_ID) = 21
AND (sp.RJ_SPAN_ID LIKE ('%SPN%') 
     OR sp.RJ_SPAN_ID LIKE ('%SPQ%') 
     OR sp.RJ_SPAN_ID LIKE ('%SPR%')    
     OR sp.RJ_SPAN_ID LIKE ('%SPS%'))
AND (sp.RJ_SPAN_ID LIKE ('%_BU') 
     OR sp.RJ_SPAN_ID LIKE ('%_MP'))
AND sp.INVENTORY_STATUS_CODE = 'IPL'
AND sp.RJ_MAINTENANCE_ZONE_CODE = 'INMUNVMB01'
AND (sp.RJ_INTRACITY_LINK_ID NOT LIKE ('%\_9%') ESCAPE '\' 
     OR sp.RJ_INTRACITY_LINK_ID IS NULL);

上面的SP返回4条记录,这些是我想要插入到表中的有效记录。

现在下面还有另一个 SP,它返回 7 条记录。

SELECT distinct  TO_CHAR(sp.RJ_SPAN_ID) AS SPAN_ID
               , TO_CHAR(sp.RJ_MAINTENANCE_ZONE_CODE) AS MAINT_ZONE_CODE
from  APP_FTTX.span@SAT sp
-- INNER JOIN APP_FTTX.transmedia@SAT tm  -- transmedia added
--  on sp.RJ_SPAN_ID = tm.RJ_SPAN_ID
-- WHERE length(sp.RJ_SPAN_ID) = length(tm.RJ_SPAN_ID)
--  and sp.RJ_MAINTENANCE_ZONE_CODE = tm.RJ_MAINTENANCE_ZONE_CODE
--   and sp.INVENTORY_STATUS_CODE = tm.INVENTORY_STATUS_CODE
WHERE LENGTH(sp.RJ_SPAN_ID) = 21
AND (sp.RJ_SPAN_ID LIKE ('%SPN%') 
     OR sp.RJ_SPAN_ID LIKE ('%SPQ%') 
     OR sp.RJ_SPAN_ID LIKE ('%SPR%')    
     OR sp.RJ_SPAN_ID LIKE ('%SPS%'))
AND (sp.RJ_SPAN_ID LIKE ('%_BU') 
     OR sp.RJ_SPAN_ID LIKE ('%_MP'))
AND sp.INVENTORY_STATUS_CODE = 'IPL'
AND sp.RJ_MAINTENANCE_ZONE_CODE = 'INMUNVMB01'
AND (sp.RJ_INTRACITY_LINK_ID NOT LIKE ('%\_9%') ESCAPE '\' 
     OR sp.RJ_INTRACITY_LINK_ID IS NULL);

SP 是相似的。第二个 SP 中有 3 条记录无效。所以我想要的是:我想将其他 3 条无效记录插入到另一个表中。

请建议如何实现。

更新

根据 Alex 的评论,我在下面的代码中实现了减号部分。

SELECT distinct  TO_CHAR(sp.RJ_SPAN_ID) AS SPAN_ID, TO_CHAR(sp.RJ_MAINTENANCE_ZONE_CODE) AS MAINT_ZONE_CODE
                                    from  APP_FTTX.span@SAT sp
                                   -- INNER JOIN APP_FTTX.transmedia@SAT tm  -- transmedia added
                                  --  on sp.RJ_SPAN_ID = tm.RJ_SPAN_ID
                                   -- WHERE length(sp.RJ_SPAN_ID) = length(tm.RJ_SPAN_ID)
                                  --  and sp.RJ_MAINTENANCE_ZONE_CODE = tm.RJ_MAINTENANCE_ZONE_CODE
                                 --   and sp.INVENTORY_STATUS_CODE = tm.INVENTORY_STATUS_CODE
                                    WHERE LENGTH(sp.RJ_SPAN_ID) = 21
                                    AND (sp.RJ_SPAN_ID LIKE ('%SPN%') OR sp.RJ_SPAN_ID LIKE ('%SPQ%') OR sp.RJ_SPAN_ID LIKE ('%SPR%')    
                                    OR sp.RJ_SPAN_ID LIKE ('%SPS%'))
                                    AND (sp.RJ_SPAN_ID LIKE ('%_BU') OR sp.RJ_SPAN_ID LIKE ('%_MP'))
                                    AND sp.INVENTORY_STATUS_CODE = 'IPL'
                                    AND sp.RJ_MAINTENANCE_ZONE_CODE = 'INMUNVMB01'
                                    AND (sp.RJ_INTRACITY_LINK_ID NOT LIKE ('%\_9%') ESCAPE '\' OR sp.RJ_INTRACITY_LINK_ID IS NULL)                                        
            MINUS

       SELECT distinct  TO_CHAR(sp.RJ_SPAN_ID) AS SPAN_ID, 
          TO_CHAR(sp.RJ_MAINTENANCE_ZONE_CODE) AS MAINT_ZONE_CODE
                                    from  APP_FTTX.span@SAT sp
                                    INNER JOIN APP_FTTX.transmedia@SAT tm  -- 
                transmedia added
                                     on sp.RJ_SPAN_ID = tm.RJ_SPAN_ID
                                    WHERE length(sp.RJ_SPAN_ID) = 
               length(tm.RJ_SPAN_ID)
                                    and sp.RJ_MAINTENANCE_ZONE_CODE = 
              tm.RJ_MAINTENANCE_ZONE_CODE
                                    and sp.INVENTORY_STATUS_CODE = 
              tm.INVENTORY_STATUS_CODE
                                    AND LENGTH(sp.RJ_SPAN_ID) = 21
                                    AND (sp.RJ_SPAN_ID LIKE ('%SPN%') OR 
                sp.RJ_SPAN_ID LIKE ('%SPQ%') OR sp.RJ_SPAN_ID LIKE ('%SPR%')    
                                        OR sp.RJ_SPAN_ID LIKE ('%SPS%'))
                                    AND (sp.RJ_SPAN_ID LIKE ('%_BU') OR 
               sp.RJ_SPAN_ID LIKE ('%_MP'))
                                    AND sp.INVENTORY_STATUS_CODE = 'IPL'
                                    AND sp.RJ_MAINTENANCE_ZONE_CODE = 
              'INMUNVMB01'
                                    AND (sp.RJ_INTRACITY_LINK_ID NOT LIKE 
               ('%\_9%') ESCAPE '\' OR sp.RJ_INTRACITY_LINK_ID IS NULL);

【问题讨论】:

  • 您没有显示任何存储过程,只是查询。我不太确定你在问什么 - 你可能只是在寻找 minus?
  • @AlexPoole:是的,我正在寻找要插入到各自表中的记录,如上所述。你有什么想法吗?而上面的查询我会把它转换成程序
  • 如果存储过程与您实际发布的代码无关,也许不提?
  • 您可以编写一个新查询来修改谓词,使其仅返回这三个记录;或者您可以减去两个现有查询以了解它们之间的区别 - 请参阅我之前链接到的文档。无论哪种方式,然后将其用作insert ... select。
  • 作为一个侧面观察,我注意到所有表引用都指向一个 db 链接 - 同一个 db 链接。这似乎很奇怪。我更希望其中一张桌子是远程的,但不是所有桌子。为什么不在 SAT 数据库中运行查询呢?你在那里做的事情可能有正当的理由,但我对使用数据库链接有误解。

标签: oracle join stored-procedures inner-join insert-update


【解决方案1】:

我认为你最好做一个LEFT JOIN。

SELECT DISTINCT sp.RJ_SPAN_ID AS SPAN_ID,
                sp.RJ_MAINTENANCE_ZONE_CODE AS MAINT_ZONE_CODE,
                SYSDATE AS MSG_DATE
FROM   APP_FTTX.span@SAT sp
WHERE  LENGTH(sp.RJ_SPAN_ID) = 21
AND REGEXP_LIKE(sp.rj_span_id, 'SP(N|Q|R|S).*_(BU|MP)$')
AND sp.INVENTORY_STATUS_CODE = 'IPL'
AND sp.RJ_MAINTENANCE_ZONE_CODE = 'INMUNVMB01'
AND NVL(INSTR(sp.RJ_INTRACITY_LINK_ID, '_'), 1) > 0
AND NOT EXISTS (SELECT 'X'
                FROM APP_FTTX.transmedia@SAT tm
                WHERE tm.rj_span_id = sp.rj_span_id
                AND tm.rj_maintenance_zone_code = sp.rj_maintenance_zone_code
                AND tm.inventory_status_code = sp.inventory_status_code);

注意NULL 检查tm.rj_span_id。鉴于我们的其他逻辑,应该保证填充该列。因为它是NULL,所以我们知道没有找到匹配项。

我还做了一些其他的调整:

  1. 在底部做length(sp.RJ_SPAN_ID) = length(tm.RJ_SPAN_ID) 是没有用的。您已经在JOIN 期间检查了这些值是否相等。如果它们的值相等,则长度必须相同。
  2. 考虑使用REGEXP_LIKE 来简化您的逻辑。类似REGEXP_LIKE(sp.rj_span_id, 'SP(N|Q|R|S).*_(BU|MP)$')
  3. 删除了列列表中的TO_CHAR。正如 cmets 中所讨论的,它们已经是字符串。
  4. 我将您的NOT LIKE 和IS NULL 更改为使用NVL 和INSTR,但这只是我的偏好(我一直在玩Code Golf,它影响了我的大脑)

至于您的INSERT,只需将SELECT 附加到INSERT INTO table_name 即可。像这样:

INSERT INTO log_table_name
  SELECT DISTINCT sp.RJ_SPAN_ID AS SPAN_ID,
                  sp.RJ_MAINTENANCE_ZONE_CODE AS MAINT_ZONE_CODE,
                  SYSDATE AS UPDATED_DATE,
                  'YOUR_USERNAME' AS USERNAME
  FROM   APP_FTTX.span@SAT sp
  WHERE  LENGTH(sp.RJ_SPAN_ID) = 21
  AND REGEXP_LIKE(sp.rj_span_id, 'SP(N|Q|R|S).*_(BU|MP)$')
  AND sp.INVENTORY_STATUS_CODE = 'IPL'
  AND sp.RJ_MAINTENANCE_ZONE_CODE = 'INMUNVMB01'
  AND NVL(INSTR(sp.RJ_INTRACITY_LINK_ID, '_'), 1) > 0
  AND NOT EXISTS (SELECT 'X'
                  FROM APP_FTTX.transmedia@SAT tm
                  WHERE tm.rj_span_id = sp.rj_span_id
                  AND tm.rj_maintenance_zone_code = sp.rj_maintenance_zone_code
                  AND tm.inventory_status_code = sp.inventory_status_code);  

注意:我对 UPDATED_BY 列进行了硬编码,因为我不知道正确的值。

【讨论】:

  • 感谢德尔的回答,如果您也可以更新插入表查询,那就太好了。那是我最受困的地方。即使我有答案,也想看看你的逻辑方式
  • @nkb 能否提供表名和结构?
  • 是的,你可以从这个链接stackoverflow.com/a/61126310/1216804得到表名和它的结构
  • @nkb 这应该会有所帮助。我不确定您将UPDATED_DATE 或UPDATED_BY 列放在哪里,所以我为您放置了占位符。
  • 谢谢 Del,我会测试它并回复你。将来需要更多帮助。
猜你喜欢
  • 2020-08-19
  • 2022-01-06
  • 1970-01-01
  • 1970-01-01
  • 2014-05-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-05
相关资源
最近更新 更多