Team LiB   Previous Section   Next Section

4.4 Adding New Individual Permissions

4.4.1 Problem

The previous recipe's solution allows you to define individual exceptions to permissions that a trader already has at the group level. However, you wish to grant permissions to specific traders without regard to whether permissions for the same products have been granted at the group level.

4.4.2 Solution

In the previous recipe, you could define an exception to a permission that a trader had already been granted at the group level. For example, you could create the following two rows in AccountPermissions:

AccountId            ProductType          Status Limit        
-------------------- -------------------- ------ ------------ 
Alex0001             Share                V      5000.00
Betty0002            Share                V      8000.00

The query in the previous recipe, however, will only respect these account-specific permissions in cases where the traders in question have also been granted permission to trade shares at the group level. This limitation, if you wish to call it that, comes about as a result of the three-way join used in the query.

You may wish account-specific permissions to take effect all the time. To do that, you can use the same data model as shown in the previous recipe, but with a different query. The query shown in the following example is a union query and correctly returns both group-level and account-specific permissions for Betty0002:

SELECT m.AccountId, g.ProductType, MIN(g.Limit) Limit
FROM GroupMembership m JOIN GroupPermissions g
   ON m.groupId=g.groupId 
WHERE Status='V' AND AccountId='Betty0002' 
   AND NOT EXISTS(SELECT * FROM AccountPermissions  a
      WHERE m.AccountId=a.AccountId AND g.ProductType=a.ProductType) 
GROUP BY m.AccountId, g.ProductType
UNION
SELECT a.AccountId, a.ProductType,a.Limit 
FROM AccountPermissions a
WHERE a.AccountId='Betty0002' AND a.Status='V'

AccountId            ProductType          Limit        
-------------------- -------------------- ------------ 
Betty0002            Share                8000.00
Betty0002            Future               200.00
Betty0002            Option               100.00

As you can see, even though Betty0002 has not been granted permission to trade shares at the group level, this query still picked up the account-level share permissions. The query in the previous recipe won't do that.

4.4.3 Discussion

The key to this query is that it is a union query. The first query in the union reports all those permissions that are defined only at the group level. The subquery in that query's WHERE clause ensures that group-level permissions for products are excluded when account-specific permissions exist for those same products. The second query in the union then returns account-specific permissions. The results from the two queries are combined as a result of the UNION clause.

There are two drawbacks to the solution shown in this recipe. One is that this solution is less efficient than the one shown in the previous recipe. This is because there are three SELECT statements involved instead of just one. Another drawback is that this solution is inflexible in terms of which permission to use when permission for the same product is granted at both the group and the account level. In such cases, the account-specific permission always takes precedence over the group-level permission. A way to overcome this latter limitation is to create a more general UNION query that includes both group- and account-level permissions, embed that query in a view, and then manipulate the view with an appropriate query. The following statement creates such a view:

CREATE VIEW Permissions 
AS
SELECT m.AccountId, g.ProductType, MIN(g.Limit) Limit
   FROM GroupMembership m JOIN GroupPermissions g
      ON m.groupId=g.groupId 
   WHERE Status='V' 
   GROUP BY m.AccountId, g.ProductType
UNION
   SELECT a.AccountId, a.ProductType,a.Limit 
   FROM AccountPermissions a
   WHERE  a.Status='V'

This VIEW returns the group permissions expanded for each account and also includes any account-specific permissions that may exist. To list all permissions for a particular account, query the view and apply your interpretation policy in the query. For example:

SELECT ProductType, MIN(Limit) Limit FROM permissions 
WHERE AccountId='Alex0001'
GROUP BY ProductType

ProductType          Limit        
-------------------- ------------ 
Bill                 10000.00
Bond                 2000.00
Future               200.00
Option               100.00
Share                1000.00

This query lists permissions for Alex0001. The MIN function resolves cases where multiple permissions exist for the same product type. When such cases occur, MIN ensures that only the lowest applicable limit is returned. To always return the highest-applicable limit, you could use the MAX function.

The solutions shown in this recipe are flexible, because they allow for easy addition of new levels to the permission structure. All you need is to add UNION clauses to your query or to your view.

    Team LiB   Previous Section   Next Section