从一个表到任何列获取公共行

时间:2017-02-03 07:56:34

标签: sql oracle

我有三张桌子:

CREATE TABLE workflow_roles (
  role_id   NUMBER       PRIMARY KEY,
  role_desc VARCHAR2(20)
);

CREATE TABLE tbl_workflow (
  workflow_id   VARCHAR2(5)  PRIMARY KEY,
  workflow_desc VARCHAR2(20)
);

CREATE TABLE workflow_detail (
  role_id     NUMBER      REFERENCES workflow_roles( role_id ),
  workflow_id VARCHAR2(5) REFERENCES tbl_workflow( workflow_id )
);

假设数据是:

INSERT INTO workflow_roles
  SELECT 1, 'Role 1' FROM DUAL UNION ALL
  SELECT 2, 'Role 2' FROM DUAL;

INSERT INTO tbl_workflow
  SELECT 'A', 'Work A' FROM DUAL UNION ALL
  SELECT 'B', 'Work B' FROM DUAL UNION ALL
  SELECT 'C', 'Work C' FROM DUAL UNION ALL
  SELECT 'D', 'Work D' FROM DUAL UNION ALL

INSERT INTO workflow_detail
  SELECT 1, 'A' FROM DUAL UNION ALL
  SELECT 1, 'B' FROM DUAL UNION ALL
  SELECT 2, 'B' FROM DUAL UNION ALL
  SELECT 2, 'C' FROM DUAL;

角色" B"存在于两个工作流程中

我想获得所选工作流程中存在的常见角色,即它应仅返回角色B

我尝试过以下方法:

select * from workflow_roles where role_id in 
(
select role_id from workflow_detail where workflow_id in (1,2)
);

但它将返回分配给给定工作流的所有角色。

我该怎么做?

3 个答案:

答案 0 :(得分:1)

使用用户定义聚合函数获取多个集合的交集的解决方案:

Oracle安装程序

首先,定义一个集合来保存工作流程:

CREATE OR REPLACE TYPE VARCHAR2s_Table IS TABLE OF VARCHAR2(4000);
/

其次,定义要在聚合过程中使用的对象:

CREATE OR REPLACE TYPE Varchar2sTableIntersection AS OBJECT(
  intersection VARCHAR2s_Table,

  STATIC FUNCTION ODCIAggregateInitialize(
    ctx         IN OUT Varchar2sTableIntersection
  ) RETURN NUMBER,

  MEMBER FUNCTION ODCIAggregateIterate(
    self        IN OUT Varchar2sTableIntersection,
    value       IN     VARCHAR2s_Table
  ) RETURN NUMBER,

  MEMBER FUNCTION ODCIAggregateTerminate(
    self        IN OUT Varchar2sTableIntersection,
    returnValue    OUT VARCHAR2s_Table,
    flags       IN     NUMBER
  ) RETURN NUMBER,

  MEMBER FUNCTION ODCIAggregateMerge(
    self        IN OUT Varchar2sTableIntersection,
    ctx         IN OUT Varchar2sTableIntersection
  ) RETURN NUMBER
);
/

CREATE OR REPLACE TYPE BODY Varchar2sTableIntersection
IS
  STATIC FUNCTION ODCIAggregateInitialize(
    ctx         IN OUT Varchar2sTableIntersection
  ) RETURN NUMBER
  IS
  BEGIN
    ctx := Varchar2sTableIntersection( NULL );
    RETURN ODCIConst.SUCCESS;
  END;

  MEMBER FUNCTION ODCIAggregateIterate(
    self        IN OUT Varchar2sTableIntersection,
    value       IN     VARCHAR2s_Table
  ) RETURN NUMBER
  IS
  BEGIN
    IF value IS NULL THEN
      NULL;
    ELSIF self.intersection IS NULL THEN
      self.intersection := value;
    ELSE
      self.intersection := self.intersection MULTISET INTERSECT value;
    END IF;
    RETURN ODCIConst.SUCCESS;
  END;

  MEMBER FUNCTION ODCIAggregateTerminate(
    self        IN OUT Varchar2sTableIntersection,
    returnValue    OUT VARCHAR2s_Table,
    flags       IN     NUMBER
  ) RETURN NUMBER
  IS
  BEGIN
    returnValue := self.intersection;
    RETURN ODCIConst.SUCCESS;
  END;

  MEMBER FUNCTION ODCIAggregateMerge(
    self        IN OUT Varchar2sTableIntersection,
    ctx         IN OUT Varchar2sTableIntersection
  ) RETURN NUMBER
  IS
  BEGIN
    IF self.intersection IS NULL THEN
      self.intersection := ctx.intersection;
    ELSIF ctx.intersection IS NULL THEN
      NULL;
    ELSE
      self.intersection := self.intersection MULTISET INTERSECT ctx.intersection;
    END IF;
    RETURN ODCIConst.SUCCESS;
  END;
END;
/

第三,创建用户定义的聚合函数:

CREATE FUNCTION MULTISET_INTERSECT( collection VARCHAR2s_Table )
RETURN VARCHAR2s_Table
PARALLEL_ENABLE AGGREGATE USING Varchar2sTableIntersection;
/

查询1 - 输出为集合

SELECT MULTISET_INTERSECT( workflows ) AS common_workflows
FROM   (
  SELECT role_id,
         CAST(
           COLLECT(
             workflow_id
           ) AS VARCHAR2s_Table
         ) AS workflows
  FROM   workflow_detail
  GROUP BY role_id
);

<强>输出

COMMON_WORKFLOWS
----------------------
VARCHAR2S_TABLE( 'B' )

查询2 - 输出为行

SELECT t.COLUMN_VALUE AS common_workflows
FROM   (
         SELECT MULTISET_INTERSECT( workflows ) AS common
         FROM   (
           SELECT role_id,
                  CAST(
                    COLLECT(
                      workflow_id
                    ) AS VARCHAR2s_Table
                  ) AS workflows
           FROM   workflow_detail
           GROUP BY role_id
         )
       ) cw
       CROSS JOIN TABLE( cw.common ) t;

<强>输出

COMMON_WORKFLOWS
----------------
B

答案 1 :(得分:0)

我通过这种方式获得所有使用数字的rols

    select  wr.role_desc role_desc, count(*) role_nums
    from workflow_detail wd
    inner join workflow_roles wr on wr.role_id =  wd.role_id
    inner join tbl_workflow tw on tw.workflow_id = wd.workflow_id
    group by wr.role_desc
    order by role_nums desc

其他

如果您需要两个工作流程之间通用的角色,则可以过滤具有conut = 2

的不同角色
select  wr.role_desc role_desc, count(disctinct wd.role_id) role_nums
from workflow_detail wd
inner join workflow_roles wr on wr.role_id =  wd.role_id
inner join tbl_workflow tw on tw.workflow_id = wd.workflow_id
where wd.workflow_id in (1,2)
group by wr.role_desc
having role_nums = 2
order by role_nums desc

答案 2 :(得分:0)

一个简单的解决方案:您希望角色分为两组,因此使用IN查询两个集:

select * from workflow_roles 
where role_id in (select role_id from workflow_detail where workflow_id = 1)
  and role_id in (select role_id from workflow_detail where workflow_id = 2);

另一种选择是计算workflow_detail中的匹配项。您正在寻找两个workflow_ids,因此请检查您是否找到了两个角色:

select * from workflow_roles 
where role_id in 
(
  select role_id 
  from workflow_detail 
  where workflow_id in (1,2)
  group by role_id
  having count(distinct workflow_id) = 2
);