2013-04-01 31 views
2

我們有一個groupuser permission表如下:刪除 「NOT IN」 子句和優化查詢

Group (group_id,name) 
01 | G1 
02 | G2 
03 | G3 
04 | G4 

UserPermission (userid,group_id,active) 
User1 | 01 | 1 
User1 | 02 | 1 
User2 | 01 | 1 
User2 | 02 | 1 
User2 | 03 | 1 
User2 | 04 | 1 
.. 
UserN | xx | 1 

每個用戶有權一個組。
但是,UserPermission表中缺少一些用戶的某些權限。

問題是爲UserPermission表中存在的所有用戶插入缺少的組權限條目。

於是我想出了一個查詢 (原油)

insert into UserPermission 
     select distinct userid, '03', 1 from UserPermission 
     where userid not in (
       select userid from UserPermission where group_id = '03' 
     ) 

這對於插入的權限缺少用戶提供Group 03 ..
其他組相似。

有沒有更好的方法來編寫上述查詢。如何優化?

+0

你在這裏說多少條記錄?你是否注意到性能問題,或者你只是問一般? – taylonr

+0

一般..但約有30個組和約7K-8K的用戶。 – Amitd

回答

3

在我的解決方案中,我從表GroupUserPermission唯一的用戶ID只有)獲得笛卡爾產品。然後使用LEFT JOIN將兩個表的產品重新連接在表UserPermission上,前提是它匹配兩列:Group_IDuserID。任何不滿足條件的記錄將在UserPermission的列上具有NULL值。這些值是UserPermission表中缺失的值。

這也將填充所有用戶的所有缺失許可

INSERT INTO UserPermission(userID, group_ID, active) 
SELECT b.userID, a.Group_ID, 1 
FROM [Group] a 
     CROSS JOIN (SELECT DISTINCT userID FROM UserPermission) b 
     LEFT JOIN UserPermission c 
      ON a.Group_ID = c.Group_ID AND 
       b.userID = c.UserID 
WHERE c.Group_ID IS NULL 

但是,如果你想插入只有特定Group_ID,那麼你需要額外的條件。

INSERT INTO UserPermission(userID, group_ID, active) 
SELECT b.userID, a.Group_ID, 1 
FROM [Group] a 
     CROSS JOIN (SELECT DISTINCT userID FROM UserPermission) b 
     LEFT JOIN UserPermission c 
      ON a.Group_ID = c.Group_ID AND 
       b.userID = c.UserID 
WHERE c.Group_ID IS NULL AND 
     a.Group_ID = 3 
     -- or change it to IN clause 
     -- if you have more Group_ID to include 
     -- a.Group_ID IN (3,4) 
+1

左贏加盟。 – Adrian

+1

通用的解決方案很不錯..沒有硬編碼required..nice! – Amitd

+1

@Amitd如果要硬編碼值,我添加了更新。 ':)' –

1

不存在通常表現比沒有好。

insert into UserPermission 
select disinct userid, '03', 1 
from UserPermission 
where not exists 
(select * 
from UserPermission 
where group_id = '03') 

另一種方式是「不」

insert into UserPermission 
select disinct userid, '03', 1 
from UserPermission 
where user_id in 
(select user_id from UserPermission 
except 
select user_id from UserPermission 
where group_id = '03') 
+0

thx爲答案:) – Amitd

1

這裏有一種方法使用「中」,而不是:

with toinsert as (
    select userid, '03' as UserPermission 
    from UserPermission up 
    group by userId 
    having sum9case when userPermission = '03' then 1 else 0 end) = 0 
) 
insert into UpserPermission 
    select userid, UserPermission 
    from toinsert; 

我已經打破了插入列表中的成CTE。你也可以這樣做,只是作爲子查詢:

insert into UserPermission 
    select userid, '03' 
    from UserPermission 
    group by userid 
    having sum(case when userpermission = '03' then 1 else 0 end) = 0 
+0

可以這個查詢是更通用? – Amitd

+1

@Amitd。 。 。絕對。對於「set-set-set」問題,使用'having by'子句的'group by'的好處在於所有條件都在'having'子句中。這可以讓你很容易地概括它。 –

+0

thx我會給它一個嘗試:) – Amitd

1

另一種可能的解決方案是使用新的MERGE語句。根據我的經驗,MERGE表現非常好。

merge UserPermission target 
using (
    -- Assuming u.userid and g.group_id are unique in their tables 
    select u.userid, g.group_id 
    from [User] u 
    cross join [Group] g 
) source on source.userid = target.userid and source.group_id = target.group_id 
when not matched then 
    insert (userid, group_id, active) 
    values (source.userid, source.group_id, 1); 
+0

thx ..沒有太多關於合併..我會嘗試一下:) – Amitd