5

一般的な従業員情報を持つ従業員テーブルがあります。ユーザー情報を含む別の User テーブル。ユーザーは従業員を作成できます。

ユーザーが従業員を作成するとき、ユーザーは部門、製品、サブ製品、および地域を従業員に割り当てます。

ユーザー自身が、特定の部門、製品、サブ製品、および地域にアクセスできます。

たとえば、ユーザー A は部門 D1、製品 P1 (地域 = アジア、アメリカ) 、P2 (地域 = アジア)、P3 (地域 = アジア、アメリカ) にアクセスできます。

Division は Product の親です。各部門は多くの製品を持つことができます。

ユーザー A が製品 P1 (地域 = アジア、アメリカ) にアクセスできると言うとき、それはユーザー A が製品 = P1 および地域 = アジアまたはアメリカで従業員を追加できることを意味します。

彼は、製品 P1 またはその他の製品自体のために従業員を他の地域に追加することはできません。

ユーザー A がデータベースに 500 人の従業員を追加したと仮定すると、別のユーザー B は別の従業員を 500 人追加した、というようになります。

アクセスできる従業員を取得するための効率的なクエリを作成するにはどうすればよいですか?

私と同じアクセス権を持つ別のユーザーが従業員を追加できる可能性があり、それらの従業員も表示できるはずです。

以下は私が持っているdbスキーマです。

        --------------------------------------------------------
    --  DDL for Table BI_DIVISION
    --------------------------------------------------------

      CREATE TABLE "HEADCOUNT_BI"."BI_DIVISION" 
       (    "DIVISION_ID" NUMBER(*,0) NOT NULL 
        "DIVISION_NAME" VARCHAR2(4000) 
       ) ;

    --------------------------------------------------------
    --  DDL for Table BI_PRODUCT
    --------------------------------------------------------

      CREATE TABLE "HEADCOUNT_BI"."BI_PRODUCT" 
       (    "PRODUCT_ID" NUMBER(*,0) NOT NULL , 
        "PRODUCT_NAME" VARCHAR2(4000), 
        "DIVISION_ID" NUMBER(*,0) 
       ) ;


    --------------------------------------------------------
    --  DDL for Table BI_SUB_PRODUCT
    --------------------------------------------------------

      CREATE TABLE "HEADCOUNT_BI"."BI_SUB_PRODUCT" 
       (    "SUB_PRODUCT_ID" NUMBER(*,0) NOT NULL, 
        "SUB_PRODUCT_NAME" VARCHAR2(4000), 
        "PRODUCT_ID" NUMBER(*,0), 
       ) ;


    --------------------------------------------------------
    --  DDL for Table BI_REGION
    --------------------------------------------------------

      CREATE TABLE "HEADCOUNT_BI"."BI_REGION" 
       (    "REGION_ID" NUMBER(*,0) NOT NULL, 
        "REGION_NAME" VARCHAR2(4000) NOT NULL ENABLE 
       ) ;


    --------------------------------------------------------
    --  DDL for Table BI_EMPLOYEE
    --------------------------------------------------------

      CREATE TABLE "HEADCOUNT_BI"."BI_EMPLOYEE" 
       (    "EMP_ID" NUMBER(*,0) NOT NULL , 
        "DIVISION_ID" NUMBER(*,0), 
        "PRODUCT_ID" NUMBER(*,0), 
        "SUB_PRODUCT_ID" NUMBER(*,0), 
        "REGION_ID" NUMBER(*,0) ,
        "CONFIDENTIAL" VARCHAR2(1) DEFAULT 'Y' 
       );


    --------------------------------------------------------
    --  DDL for Table BI_USER
    --------------------------------------------------------

      CREATE TABLE "HEADCOUNT_BI"."BI_USER" 
       (    "USER_ID" NUMBER(*,0) NOT NULL, 
        "FIRSTNAME" VARCHAR2(4000), 
        "LASTNAME" VARCHAR2(4000) 
       ) ;


    --------------------------------------------------------
    --  DDL for Table BI_USER_ACCESS
    --------------------------------------------------------

      CREATE TABLE "HEADCOUNT_BI"."BI_USER_ACCESS" 
       (    "USER_ACCESS_ID" NUMBER(*,0) NOT NULL, 
        "USER_ID" NUMBER(*,0), 
        "DIVISION_ID" NUMBER(*,0), 
        "PRODUCT_ID" NUMBER(*,0), 
        "SUB_PRODUCT_ID" NUMBER(*,0), 
        "REGION_ID" NUMBER(*,0), 
        "ACCESS_LEVEL" NUMBER(*,0), 
        "CONFIDENTIAL" VARCHAR2(1) DEFAULT 'Y' 
       ) ;

    Insert into BI_DIVISION (DIVISION_ID,DIVISION_NAME) values (1,'DIVISION 1');
    Insert into BI_DIVISION (DIVISION_ID,DIVISION_NAME) values (2,'DIVISION 2');

    Insert into BI_PRODUCT (PRODUCT_NAME,DIVISION_ID,PRODUCT_ID) values ('PRODUCT 1',1,1);
    Insert into BI_PRODUCT (PRODUCT_NAME,DIVISION_ID,PRODUCT_ID) values ('PRODUCT 2',1,2);
    Insert into BI_PRODUCT (PRODUCT_NAME,DIVISION_ID,PRODUCT_ID) values ('PRODUCT 3',2,3);
    Insert into BI_PRODUCT (PRODUCT_NAME,DIVISION_ID,PRODUCT_ID) values ('PRODUCT 4',2,4);

    Insert into BI_SUB_PRODUCT (SUB_PRODUCT_ID,SUB_PRODUCT_NAME,PRODUCT_ID) values (1,'SUB PRODUCT 1', 1);
    Insert into BI_SUB_PRODUCT (SUB_PRODUCT_ID,SUB_PRODUCT_NAME,PRODUCT_ID) values (2,'SUB PRODUCT 2', 1);
    Insert into BI_SUB_PRODUCT (SUB_PRODUCT_ID,SUB_PRODUCT_NAME,PRODUCT_ID) values (3,'SUB PRODUCT 3', 2);
    Insert into BI_SUB_PRODUCT (SUB_PRODUCT_ID,SUB_PRODUCT_NAME,PRODUCT_ID) values (4,'SUB PRODUCT 4', 2);
    Insert into BI_SUB_PRODUCT (SUB_PRODUCT_ID,SUB_PRODUCT_NAME,PRODUCT_ID) values (5,'SUB PRODUCT 5', 3);


    Insert into BI_REGION (REGION_ID,REGION_NAME) values (1,'Americas');
    Insert into BI_REGION (REGION_ID,REGION_NAME) values (2,'Asia');
    Insert into BI_REGION (REGION_ID,REGION_NAME) values (3,'Germany');
    Insert into BI_REGION (REGION_ID,REGION_NAME) values (4,'Japan');
    Insert into BI_REGION (REGION_ID,REGION_NAME) values (5,'Pacific');
    Insert into BI_REGION (REGION_ID,REGION_NAME) values (6,'ROE');
    Insert into BI_REGION (REGION_ID,REGION_NAME) values (7,'United Kingdom');

    Insert into BI_USER (USER_ID,FIRSTNAME,LASTNAME) values (1,'Adam,'Smith);
    Insert into BI_USER (USER_ID,FIRSTNAME,LASTNAME) values (2,'Steve','Jones');

    -- user with user id = 1 has access to division 1 , product 1 , sub product 1 in regons americas, asia, germany with ACCESS_LEVEL = write access (2) and also access to confidential data 
    Insert into BI_USER_ACCESS (USER_ACCESS_ID,USER_ID,DIVISION_ID,PRODUCT_ID,SUB_PRODUCT_ID,REGION_ID,ACCESS_LEVEL, CONFIDENTIAL) values (1,1,1,1,1,1,2,'Y');
    Insert into BI_USER_ACCESS (USER_ACCESS_ID,USER_ID,DIVISION_ID,PRODUCT_ID,SUB_PRODUCT_ID,REGION_ID,ACCESS_LEVEL, CONFIDENTIAL) values (1,1,1,1,1,2,2,'Y');
    Insert into BI_USER_ACCESS (USER_ACCESS_ID,USER_ID,DIVISION_ID,PRODUCT_ID,SUB_PRODUCT_ID,REGION_ID,ACCESS_LEVEL, CONFIDENTIAL) values (1,1,1,1,1,3,2,'Y');

    -- user with user id = 1 has access to division 1 , product 2 , sub product 4 in regons americas, asia, germany with ACCESS_LEVEL = write access (2) and also NO access to confidential data 
    Insert into BI_USER_ACCESS (USER_ACCESS_ID,USER_ID,DIVISION_ID,PRODUCT_ID,SUB_PRODUCT_ID,REGION_ID,ACCESS_LEVEL, CONFIDENTIAL) values (1,1,1,2,4,1,2,'N');
    Insert into BI_USER_ACCESS (USER_ACCESS_ID,USER_ID,DIVISION_ID,PRODUCT_ID,SUB_PRODUCT_ID,REGION_ID,ACCESS_LEVEL, CONFIDENTIAL) values (1,1,1,2,4,2,2,'N');
    Insert into BI_USER_ACCESS (USER_ACCESS_ID,USER_ID,DIVISION_ID,PRODUCT_ID,SUB_PRODUCT_ID,REGION_ID,ACCESS_LEVEL, CONFIDENTIAL) values (1,1,1,2,4,3,2,'N');

    -- employees in division 1 , product 1, sub product 1 and region americas and not confi.
    Insert into BI_EMPLOYEE (EMP_ID,DIVISION_ID,PRODUCT_ID,SUB_PRODUCT_ID,REGION_ID,CONFIDENTIAL) values (1,'1','1','1',1,'N');
    Insert into BI_EMPLOYEE (EMP_ID,DIVISION_ID,PRODUCT_ID,SUB_PRODUCT_ID,REGION_ID,CONFIDENTIAL) values (2,'1','1','1',1,'N');
    Insert into BI_EMPLOYEE (EMP_ID,DIVISION_ID,PRODUCT_ID,SUB_PRODUCT_ID,REGION_ID,CONFIDENTIAL) values (3,'1','1','1',2,'N');
    Insert into BI_EMPLOYEE (EMP_ID,DIVISION_ID,PRODUCT_ID,SUB_PRODUCT_ID,REGION_ID,CONFIDENTIAL) values (4,'1','1','1',2,'N');
    Insert into BI_EMPLOYEE (EMP_ID,DIVISION_ID,PRODUCT_ID,SUB_PRODUCT_ID,REGION_ID,CONFIDENTIAL) values (5,'1','1','1',7,'N');

    Insert into BI_EMPLOYEE (EMP_ID,DIVISION_ID,PRODUCT_ID,SUB_PRODUCT_ID,REGION_ID,CONFIDENTIAL) values (11,'1','1','2',1,'N');
    Insert into BI_EMPLOYEE (EMP_ID,DIVISION_ID,PRODUCT_ID,SUB_PRODUCT_ID,REGION_ID,CONFIDENTIAL) values (12,'1','1','2',2,'N');
    Insert into BI_EMPLOYEE (EMP_ID,DIVISION_ID,PRODUCT_ID,SUB_PRODUCT_ID,REGION_ID,CONFIDENTIAL) values (13,'1','1','2',3,'N');
    Insert into BI_EMPLOYEE (EMP_ID,DIVISION_ID,PRODUCT_ID,SUB_PRODUCT_ID,REGION_ID,CONFIDENTIAL) values (14,'1','1','2',2,'N');
    Insert into BI_EMPLOYEE (EMP_ID,DIVISION_ID,PRODUCT_ID,SUB_PRODUCT_ID,REGION_ID,CONFIDENTIAL) values (15,'1','1','2',3,'N');

    Insert into BI_EMPLOYEE (EMP_ID,DIVISION_ID,PRODUCT_ID,SUB_PRODUCT_ID,REGION_ID,CONFIDENTIAL) values (111,'2','3','5',1,'N');
    Insert into BI_EMPLOYEE (EMP_ID,DIVISION_ID,PRODUCT_ID,SUB_PRODUCT_ID,REGION_ID,CONFIDENTIAL) values (112,'2','3','5',2,'N');
    Insert into BI_EMPLOYEE (EMP_ID,DIVISION_ID,PRODUCT_ID,SUB_PRODUCT_ID,REGION_ID,CONFIDENTIAL) values (113,'2','3','5',3,'N');
    Insert into BI_EMPLOYEE (EMP_ID,DIVISION_ID,PRODUCT_ID,SUB_PRODUCT_ID,REGION_ID,CONFIDENTIAL) values (114,'2','3','5',4,'N');
    Insert into BI_EMPLOYEE (EMP_ID,DIVISION_ID,PRODUCT_ID,SUB_PRODUCT_ID,REGION_ID,CONFIDENTIAL) values (115,'2','3','5',5,'N');

以下はこれまでに書いたクエリですが、それが最善の方法であるかどうかはわかりません。

    SELECT 
  *
FROM 
  BI_EMPLOYEE e 
JOIN BI_USER_ACCESS uad On uad.DIVISION_ID = e.DIVISION_ID and uad.USER_ID = 137
JOIN BI_USER_ACCESS uap On uap.PRODUCT_ID = e.PRODUCT_ID and uap.USER_ID = 137
JOIN BI_USER_ACCESS uasp On uasp.SUB_PRODUCT_ID = e.SUB_PRODUCT_ID and uasp.USER_ID = 137
JOIN BI_USER_ACCESS uar On uar.REGION_ID = e.REGION_ID  and uar.SUB_PRODUCT_ID = e.SUB_PRODUCT_ID and uar.USER_ID = 137

編集1:

db スクリプトといくつかのサンプル データを使用して質問を更新しました。

4

3 に答える 3

1

あなたの質問は、ユーザーが従業員のリストにアクセスできるようにするための最速の方法を具体的に尋ねています。だから私はそれに答えます。

私は数年前に同様のシステムで作業していましたが、この情報を非常に迅速に評価できることが重要でした。原則は同じですが、さらに多くの基準(部門、製品、地域、国、都市、ユニット、部門など)がありました。

パフォーマンスが本当に重要な場合は、クエリの結果をテーブルに具体化する価値があります。ACL_CACHE(USER_ID, EMP_ID)

ユーザーが従業員にアクセスできるようにするためのクエリは、簡単になります。

SELECT EMP_ID
FROM ACL_CACHE
WHERE USER_ID = ####

ACL_CACHEアクセスレベルに基づいてユーザーが表示できる結果を制限する場合は、テーブルを他のクエリに結合することもできます。

これは非常にうまく機能し、多数の従業員やユーザーと作業するときに大きなメリットをもたらします。通常、最大500,000レコードを処理していました。

ACL_CACHE欠点は、明らかにテーブルを最新の状態に保つ必要があることです。これは、他のいくつかのトランザクションが少し遅くなる可能性があることを意味します。たとえば、新しい従業員を追加するときはACL_CACHE、新しい従業員を表示できるすべてのユーザーのテーブルにもレコードを追加する必要があります。

In our experience, the extra delay on these kind of transactions isn't noticeable for the user and is well worth the sacrifice to have all read-only transactions work an order of magnitude faster.

Alternatively, you can update the ACL_CACHE table as a nightly job in one mass update, if you can put up with the data being up to 24 hours "old". Since your tables are called "HEADCOUNT_BI" I'm guessing it may be acceptable if your headcount reports are always accurate up to yesterday evening.

于 2012-07-17T13:39:34.587 に答える
1

ユーザーがアクセスできる従業員のリストは、次のようなクエリで取得できます。

SELECT * 
  FROM bi_employee e
 WHERE EXISTS (SELECT NULL
                 FROM bi_user_access ua
                WHERE ua.division_id = e.division_id
                  AND ua.product_id = e.product_id
                  AND ua.sub_product_id = e.sub_product_id
                  AND ua.region_id = e.region_id
                  AND (e.confidential = 'N' OR ua.confidential = 'Y')
                  AND ua.user_id = :user_id);

データ サンプルでは、​​ユーザー 1 は従業員 1 から 4 にアクセスできます。

于 2012-07-13T08:20:02.027 に答える
0

USER_ACCESSこのクエリは、テーブルをテーブルに結合しEMPLOYEEます。USER_ACCESS提供された (137) でテーブルをフィルタリングし、USER_ID次に結合すると、テーブルに存在するものと同じレコードEMPLOYEEを持つ従業員のみが返されます。DIVISION_IDPRODUCT_IDUSER_ACCESS

select  e.*
from    BI_USER_ACCESS a
join    BI_EMPLOYEE e
on      a.DIVISION_ID = e.DIVISION_ID
and     a.PRODUCT_ID = e.PRODUCT_ID
where   a.USER_ID = 137

EMPLOYEEデータ (e.*)のみを選択しますが、必要に応じUSER_ACCESSてテーブルをテーブルに結合し、USERユーザー データも返すことができます (たとえば)。EMPLOYEEしかし、 の 2 つのフィールドに基づいてデータを返すには、USER_ACCESSそれで十分です。

それはあなたが望んでいたものを手に入れますか?

于 2012-07-10T12:16:35.227 に答える