oracle 条件检查以获取输出

vmjh9lq9  于 2022-11-22  发布在  Oracle
关注(0)|答案(3)|浏览(146)

我有2个表name和match。name和match表都有列类型。name表中的列和数据

ID| type  |
--| ----  |
 1| 1ABC  |
 2| 2DEF  |
 3| 3DEF  |
 4| 4IJK  |

匹配表中的列和数据为
| 类型|数据库|
| - -|- -|
| 非%ABC%且非%DEF%|非ABC和非DEF|
| %定义%|仅DEF|
| 不是%DEF%且不是%IJK%|非DEF和非IJK|
我试过使用case语句。如果匹配表中的类型为NOT,则前3个字符将为NOT。下面的查询显示缺少关键字错误。我不确定此处缺少了什么

SELECT s.id, s.type, m.data
where case when substr(m.type1,3)='NOT' then s.type not in (REPLACE(REPLACE(m.type,'NOT',''),'AND',','))
          ELSE s.type in (m.type) end
from source s, match m;

我需要输出与源列中的类型匹配,并在匹配列中显示数据。
输出应为

ID|type|DATA
1 |1ABC|NOT DEF AND NOT IJK
2 |2DEF|DEF ONLY
3 |3DEF|DEF ONLY
4 |4IJK|NOT ABC AND NOT DEF
5lhxktic

5lhxktic1#

您 尝试 的 查询 的 最 大 问题 似乎 是 SQL 要求 WHERE 子句 在 FROM 子句 之后 。
但是 , 您 的 查询 在 其他 方面 也 存在 缺陷 。 尽管 CASE 语句 中 可能 包含 复杂 的 逻辑 ( 包括 子 查询 ) , 但 它 最终 必须 返回 一 个 常量 。 其中 的 条件 不会 像 在 主 查询 的 WHERE 子句 中 那样 应用 ( 就 像 您 试图 做 的 那样 ) 。
我 的 建议 是 不要 像 现在 这样 存储 match 表 。 最 好 有 一 个 包含 要 计算 的 每个 条件 的 表 。 假设 这 不 可能 , 我 建议 先 用 CTE ( 甚至 是 视图 ) 来 分解 它 。
此 查询 ( based on Nefreo's answer for breaking strings into multiple rows ) ...

SELECT 
  data,
  regexp_count(m.type, ' AND ')  + 1 num,
  CASE WHEN REGEXP_SUBSTR(m.type,'(.*?)( AND |$)',1,levels.column_value) like 'NOT %' THEN 1 ELSE 0 END negate,
  replace(replace(REGEXP_SUBSTR(m.type,'(.*?)( AND |$)',1,levels.column_value), 'NOT '), ' AND ') match
 FROM match m INNER JOIN
  table(cast(multiset(select level from dual connect by level <= regexp_count(m.type, ' AND ')  + 1) as sys.OdciNumberList)) levels
   ON 1=1

中 的 每 一 个
... 将 您 的 匹配 表 分解 为 类似 以下 的 内容 :
| 数据 库|数量|否定|匹配|
| - -| - -| - -| - -|
| 非 ABC 和 非 DEF| 2 个|一 个|% ABC %|
| 非 ABC 和 非 DEF| 2 个|一 个|% 定义 %|
| 仅 DEF|一 个|第 0 页|% 定义 %|
| 非 DEF 和 非 IJK| 2 个|一 个|% 定义 %|
| 非 DEF 和 非 IJK| 2 个|一 个|% IJK %|
因此 , 我们 现在 知道 了 每个 特定 的 like 条件 , 它 是否 应该 取 反 , 以及 每个 MATCH 行 需要 匹配 的 条件 数 。( 为了 简单 起见 , 我 使用 match.data 作为 此 操作 的 关键 字 , 因为 它 对于 match 中 的 每 一 行 都 是 唯一 的 , 而且 是 我们 无论 如何 都 要 返回 的 ,但 如果 实际 上 是 以 这种 方式 存储 数据 , 则 可能 会 使用 某种 序列 , 而 不会 重复 人类 可读 的 文本 。 )
这样 , 您 的 最终 查询 就会 非常 简单 :

SELECT name.id, name.type, criteria.data
FROM name INNER JOIN criteria
  ON
   (criteria.negate = 0 AND name.type LIKE criteria.match)
   OR
   (criteria.negate = 1 AND name.type NOT LIKE criteria.match)
GROUP BY name.id, name.type, criteria.data
HAVING COUNT(*) = MAX(criteria.num)
ORDER BY name.id

格式
ON 中 的 条件 执行 相应 的 LIKENOT LIKE ( 匹配 CRITERIA 视图/CTE 中 的 一 个 条件 ) , HAVING 中 的 条件 确保 我们 具有 正确 的 总 匹配 数 来 返回 该行 ( 确保 我们 匹配 MATCH 表 的 一 行 中 的 所有 条件 ) 。
你 可以 看到 整个 事情 ...

WITH criteria AS
(
 SELECT 
  data,
  regexp_count(m.type, ' AND ')  + 1 num,
  CASE WHEN REGEXP_SUBSTR(m.type,'(.*?)( AND |$)',1,levels.column_value) like 'NOT %' THEN 1 ELSE 0 END negate,
  replace(replace(REGEXP_SUBSTR(m.type,'(.*?)( AND |$)',1,levels.column_value), 'NOT '), ' AND ') match
 FROM match m INNER JOIN
  table(cast(multiset(select level from dual connect by level <= regexp_count(m.type, ' AND ')  + 1) as sys.OdciNumberList)) levels
   ON 1=1
)
SELECT name.id, name.type, criteria.data
FROM name INNER JOIN criteria
  ON
   (criteria.negate = 0 AND name.type LIKE criteria.match)
   OR
   (criteria.negate = 1 AND name.type NOT LIKE criteria.match)
GROUP BY name.id, name.type, criteria.data
HAVING COUNT(*) = MAX(criteria.num)
ORDER BY name.id

格式
... 工作 in this fiddle
作为 一次性 的 , 我 不 认为 这 与 已经 提供 的 另 一 个 答案 有 显著 不同 , 但 我 想 这样 做 , 因为 我 认为 如果 条件 的 复杂 性 发生 变化 , 这 可能 更 容易 维护 。
它 已经 处理 了 任意 数量 的 条件 , 在 MATCH 的 同一 行 中 混合 了 NOT 和 not - NOT , 并 允许 使用 % 符号( 对于 like ) 可 任意 放置( 例如 startswith%%endswith%contains%start%somewhere%endexactmatch 应该 都 能 正常 工作 ) . 如果 将来 要 添加 不同 类型 的 条件 或 处理 OR s ,我 认为 这里 的 一般 思想 是 适用 的 。

tvokkenx

tvokkenx2#

在不知道其他可能的选择行规则的情况下,仅使用问题中的数据,也许您可以使用以下规则:

WITH 
    tbl_name AS
      (
          Select 1 "ID", '1ABC' "A_TYPE" From Dual Union All
          Select 2 "ID", '2DEF' "A_TYPE" From Dual Union All
          Select 3 "ID", '3DEF' "A_TYPE" From Dual Union All            
          Select 4 "ID", '4IJK' "A_TYPE" From Dual 
      ),
    tbl_match AS
      (
          Select 'NOT %ABC% AND NOT %DEF%' "A_TYPE", 'NOT ABC AND NOT DEF' "DATA" From Dual Union All
          Select '%DEF%'                   "A_TYPE", 'DEF ONLY'            "DATA" From Dual Union All
          Select 'NOT %DEF% AND NOT %IJK%' "A_TYPE", 'NOT DEF AND NOT IJK' "DATA" From Dual 
      )
Select 
    n.ID "ID", 
    n.A_TYPE, 
    m.DATA
From 
    tbl_match m 
Inner Join
    tbl_name n ON (1=1)
Where 
    (
        INSTR(m.A_TYPE, 'NOT %' || SubStr(n.A_TYPE, 2) || '%', 1, 1) = 0
      AND
        INSTR(m.A_TYPE, 'NOT %' || SubStr(n.A_TYPE, 2) || '%', 1, 2) = 0 
      AND
        Length(m.A_TYPE) > Length(SubStr(n.A_TYPE, 2)) + 2
    )
  OR
    (
        Length(m.A_TYPE) = Length(SubStr(n.A_TYPE, 2)) + 2
      AND
        '%' || SubStr(n.A_TYPE, 2) || '%' = m.A_TYPE
    )
Order By n.ID

结果:
| 识别码|类型|数据库|
| - -|- -|- -|
| 一个|1ABC公司|非DEF和非IJK|
| 2个|双DEF|仅DEF|
| 三个|三防|仅DEF|
| 四个|4IJK|非ABC和非DEF|
任何其他格式的条件应单独评估...
此致

eufgjt7s

eufgjt7s3#

WITH match_cte AS (
    SELECT m.data
          ,m.type
          ,decode(instr(m.type,'NOT')
                 ,1 -- found at position 1
                 ,0
                 ,1) should_find_str_1
          ,substr(m.type
                 ,instr(m.type,'%',1,1) + 1
                 ,instr(m.type,'%',1,2) - instr(m.type,'%',1,1) - 1) str_1
          ,decode(instr(m.type,'NOT',instr(m.type,'%',1,2))
                 ,0 -- no second NOT
                 ,1
                 ,0) should_find_str_2
          ,substr(m.type
                  ,instr(m.type,'%',1,3) + 1
                  ,instr(m.type,'%',1,4) - instr(m.type,'%',1,3) - 1) str_2
      FROM match m
)
SELECT s.id
      ,s.type
      ,m.data
  FROM source s
      CROSS JOIN match_cte m
 WHERE m.should_find_str_1 = sign(instr(s.type,m.str_1))
 AND  (m.str_2 IS NULL
         OR m.should_find_str_2 = sign(instr(s.type, m.str_2))
      )
ORDER BY s.id, m.data

匹配热膨胀系数| 数据库|型号|应查找字符串1|字符串_1|应查找字符串2|字符串_2||-|-|-|-|-|-||非ABC和非DEF|非%ABC%且非%DEF%|0|ABC公司|0|定义||定义| %定义%|1|定义|1|空值||非DEF和非IJK|不是%DEF%且不是%IJK%|0|定义|0|IJK公司|

相关问题