Oracle中的子集匹配

goqiplq2  于 2023-06-22  发布在  Oracle
关注(0)|答案(2)|浏览(111)

我有以下两个表,pod_labelservice_selector

create table pod_label (
    name varchar2(256),
    key varchar2(256),
    value varchar2(256)
);

insert into pod_label (name, key, value)
values ('p1', 'l1', '1');
insert into pod_label (name, key, value)
values ('p1', 'l2', '2');
insert into pod_label (name, key, value)
values ('p1', 'l3', '3');

insert into pod_label (name, key, value)
values ('p2', 'l1', '1');

insert into pod_label (name, key, value)
values ('p3', 'l1', 'N/A');

| 名称|关键字|价值|
| - -----|- -----|- -----|
| p1| L1| 1|
| p1| L2| 2|
| p1| L3| 3|
| P2| L1| 1|
| p3| L1|不适用|

create table service_selector (
    name varchar2(256),
    key varchar2(256),
    value varchar2(256)
);

insert into service_selector (name, key, value)
values ('s1', 'l1', '1');
insert into service_selector (name, key, value)
values ('s1', 'l2', '2');

| 名称|关键字|价值|
| - -----|- -----|- -----|
| s1| L1| 1|
| s1| L2| 2|
我想在pod_label中找到name,使得相应的(key, value)对是service_selectors1对的超集。在上面的例子中,p1是匹配的,而p2p3不是。
一个直接的JOIN不会这样做。有没有一种方法w/out诉诸PL/SQL函数?

rvpgvaaj

rvpgvaaj1#

您可以创建以下类型:

CREATE TYPE key_value_pair AS OBJECT(
  key   VARCHAR2(256),
  value VARCHAR2(256)
);

CREATE TYPE key_value_list AS TABLE OF key_value_pair;

然后,您可以将值聚合到集合中,并使用SUBMULTISET OF运算符来比较集合,并确保其中一个是另一个的子集:

SELECT name, key, value
FROM   (
  SELECT name,
         key,
         value,
         CAST(
           COLLECT(key_value_pair(key, value)) OVER (PARTITION BY name)
           AS key_value_list
         ) AS kvs
  FROM   pod_label
) pl
WHERE  EXISTS(
         SELECT 1
         FROM   service_selector ss
         GROUP BY name
         HAVING CAST(
                  COLLECT(key_value_pair(ss.key, ss.value))
                  AS key_value_list
                ) SUBMULTISET OF pl.kvs
       );

对于样本数据,输出:
| 名称|关键字|价值|
| - -----|- -----|- -----|
| p1| L1| 1|
| p1| L2| 2|
| p1| L3| 3|
fiddle

bqjvbblv

bqjvbblv2#

你可以使用与本题相同的方法:SQL query: Simulating an "AND" over several rows instead of sub-querying。其思想是:

  • 按值列表匹配行
  • 计数每个键匹配的行数
  • 只选择那些匹配项的数量等于一定数量的条件(列表的长度)的键

要将此方法外推到由某列标识的多个列表,您可以使用分析countpartition by该列。

with vals_per_service as (
  /*Number of criteria per service*/
  select
    s.*,
    count(1) over(partition by name) as s_cnt
  from service_selector s
)
, pod_match as (
  select
    s.name as service_name,
    p.*,
    s.s_cnt,
    /*Number of matches per pod and service*/
    count(1) over(partition by s.name, p.name) as match_cnt
  from vals_per_service s
    left join pod_label p
    on p.key = s.key
    and p.value = s.value
)
select *
from pod_match
/*Pods that matched by all criteria*/
where s_cnt = match_cnt
--  or name is null /*If you want selectors without matches*/
order by 1,2

对于此示例数据(由其他选择器扩展):

select *
from pod_label

| 名称|关键字|价值|
| - -----|- -----|- -----|
| p1| L1| 1|
| p1| L2| 2|
| p1| L3| 3|
| P2| L1| 1|
| P2| L3| 3|
| p3| L1|不适用|

select *
from service_selector

| 名称|关键字|价值|
| - -----|- -----|- -----|
| s1| L1| 1|
| s1| L2| 2|
| S2| L1| 1|
| S3| L1| 1|
| S3| L3|无|
返回:
| 服务名称|名称|关键字|价值|S_CNT| MATCH_CNT|
| - -----|- -----|- -----|- -----|- -----|- -----|
| s1| p1| L1| 1| 2| 2|
| s1| p1| L2| 2| 2| 2|
| S2| p1| L1| 1| 1| 1|
| S2| P2| L1| 1| 1| 1|
fiddle

相关问题