Handling table with multiple child entities with Discriminators - sql

I have a user table with different types of users. The type of the user is determined by user_type column in user table. I have a company table which has one to many relationship with User. I have different classes for different users like Guest, Admin (children of User class) each with a discriminator value.
My Company class has:
private Set<Guest> guests;
private Set<Admin> admins;
How can I write a single hql query to join company and user table to populate guest users into guest set and admin users into admin set?
Like select company left outer join fetch company.guests left outer join admin.guests. I cannot find a way to include user_type while making these joins.

Related

Find user name for multiple user id columns

I am working with an existing database structure (I'm aware the structure might not be perfect, but it is out of my control). I have one table called Users with user id and name among other irrelevant columns.
My problem is with combining users and the table called settlements. The columns in settlements are as following: Case_ID, created_date, approve_date, approving_user_id, control_date, controlling_user_id
How do I interact between the two tables so that my end result shows the names of the ones approving/controlling and not the ID.
I have tried to work with joins but I don't know how to proceed when there are two different users that have approved and controlled.
select
u.user_id, u.agent_name, s.creating_date, s.approving_date,
s.approving_user, s.controlling_date, s.controlling_user
from USERS u
left join SETTLEMENTS s on u.user.id = s.approving_user
I know that I could join them in too two different tables, one called approve and one control but I would prefer to have the end result in the same table.
You want two joins, but you should start with settlements and then bring in the two users tables:
select s.approving_user, s.controlling_date, s.controlling_user,
s.creating_date, s.approving_date,
ua.user_id as approving_user_id, ua.agent_name as approving_agent_name,
uc.user_id as controlling_user_id, uc.agent_name as controlling_agent_name
from settlements s left join
users ua
on ua.user.id = s.approving_user left join
users uc
on uc.user_id = s.controlling_user_id

How to build permissions for logged user?

I have system that has different levels for users depends on what is assigned upon their account was created. So there is four different levels 1,2,3 and 4. First level have full access and then each level below narrows down to data access. So once user logged in I should get records from my Permissions table. One account can have more than one record in permissions table. Here is example:
AccountID UserName AccessLevel AccessType State City Building
FB3064A7 jfakey S F 05 NULL NULL
FB3064A7 jfakey S F 07 NULL NULL
You can see there is AccessLevel column that can have Region R, State S, City C or Building B. If user has assigned Region access there should be only one record. If there is any other access level (S,C or B) then user can have multiple records. Example above has State level. There is two different states assigned to that account and my query will return two rows. I'm wondering should I split this in two separate queries or stick with once query and merge the rows? I'm wondering what would be more efficient since this is login page there is a lot of hits. Here is example of my query:
SELECT A.AccountID, A.UserName,
P.AccessLevel, P.AccessType, P.State, P.City, P.Building
FROM Accounts AS A WITH (NOLOCK)
INNER JOIN Permissions AS P WITH (NOLOCK)
ON A.AccountID = P.AccountID
WHERE UserName = 'jfakey'
Query above is what I have now and that returns two rows. If anyone have suggestion on what is the best approach please let me know.

How to select data from a table which has inter-related data?

I have an Oracle table OBJECTS with columns Id, parent id, object_type and name.
I have real time object types as Groups, Accounts and Services. They are hierarchical in the same order. That means, Groups contains Accounts and Accounts contains Services. So, service.parent_id will refer to account.object_id and account.parent_id will refer to group.object_id within the same table.
Criteria fields for selecting data must be passed as parameters to the query. Now, if the User provides a Group ID, then the query must fetch all Services that are belonged to all the Accounts within that group.
Similarly, if the user provides ID for Account, the query must return all the Services under the Account.
I have written the following query, but it doesn't work exactly I need. Can someone help me fix it?
WITH services AS
(SELECT nco.object_id,
nco.parent_id,
nco.object_type_id,
nco.name
FROM objects nco
WHERE nco.object_type_id = 9146522450013755288 ),
accounts AS
(SELECT nco.object_id,
nco.parent_id,
nco.name
FROM objects nco,
services ss
WHERE nco.object_type_id=9145485031713653586
AND nco.object_id = ss.parent_id ),
groups AS
(SELECT nco.object_id,
nco.parent_id,
nco.name
FROM objects nco,
accounts sa
WHERE nco.object_id = sa.parent_id
AND nco.object_type_id = 9146513648413722258 )
SELECT *
FROM services ss,
accounts sa,
groups sg
WHERE ss.object_id IN (#Services#)
OR sa.object_id IN (#Accounts#)
OR sg.object_id IN (#Groups#)
Input is passed as Macros using (##) and there can be multiple Group ID's, Account ID's and Service ID's passed. object_type_id is a column which will identify what type of object it is. For example, 9146513648413722258 refers to Services, 9145485031713653586 refers to Accounts etc.
In your case, an inner join makes more sense that a full join ,, therefore
SELECT services.*
FROM objects groups
INNER JOIN objects accounts
ON groups.object_type_id=9146522450013755288
AND accounts.object_type_id=9146513648413722258
AND accounts.parent_id=groups.object_id
INNER JOIN objects services
ON services.object_type_id=9145485031713653586
AND services.parent_id=accounts.object_id
WHERE services.object_id IN (#Services#)
OR accounts.object_id IN (#Accounts#)
OR groups.object_id IN (#Groups#)
The query joins the services, accounts and groups table (implicitly from the objects table) using the parent_id and then filter out the result.

SQL query join different tables based on value in a given column?

Well I am designing a domain model and data mapper system for my site. The system has different kind of user domain objects, with the base class for users with child classes for admins, mods and banned users. Every domain object uses data from a table called 'users', while the child classes have an additional table to store admin/mod/banned information. The user type is determined by a column in the table 'users' called 'userlevel', its value is 3 for admins, 2 for mods, 1 for registered users and -1 for banned users.
Now it comes a problem when I work on a members list feature for my site, since the members list is supposed to load all users from the database(with pagination, but lets not worry about this now). The issue is that I want to load the data from both the base user table and additional admin/mod/banned table. As you see, the registered users do not have additional table to store extra data, while for admin/mod/banned users the table is different. Moreover, the columns in these tables are also different.
So How am I supposed to handle this situation using SQL queries? I know I can simply just select from the base user table and then use multiple queries to load additional data if the user level is found to be a given value, but this is a bad idea since it will results in n+1 queries for n admins/mods/banned users, a very expensive trip to database. What else am I supposed to do? Please help.
If you want to query all usertypes with one query you will have to have the columns from all tables in your result-table, several of them filled with null-values.
To get them filled with data use a left-join like this:
SELECT *
FROM userdata u
LEFT OUTER JOIN admindata a
ON ( u.userid = a.userid
AND u.usertype = 3 )
LEFT OUTER JOIN moddata m
ON ( u.userid = m.userid
AND u.usertype = 2 )
LEFT OUTER JOIN banneddata b
ON ( u.userid = b.userid
AND u.usertype = -1 )
WHERE...
You could probably drop the usertype-condition, since there should only be data in one of the joined tables, but you never know...
Then your program-code will have the job to pick the correct columns based on the usertype.
P.S.: Not that select * is only for sake of simplicity, in real code better list all of the column-names...
While is totally fine having this hierarchy in your domain classes, I would suggest changing the approach in your database. Otherwise your queries are going to be very complex and slow.
You can have just another table called e.g. users_additional_info with the mix of the columns that you need for all your user types. Then you can do
SELECT * FROM users
LEFT JOIN users_additional_info ON users.id = users_additional_info.user_id
to get all the information in a single simple query. Believe me or not, this approach will save you a lots of headaches in the future when your tables start to grow or you decide to add another type of user.

SQL Insert based on role

I have a database with 3 tables:
Table 1 (Department) - This is a table with columns for departments and departmentID's
Table 2 (SecurityMap) - This is a table that maps rolenames to department ID's
Table 3 (customer info) - this is the info that is displayed to users based on their role memberships
I have all of the SELECT based on role functions working.
What I need is to figure out how to insert a specific value into the DepartmentID column within Table 3 by default, based on the users role membership. For instance, when someone is adding a new row to the database - in addition to the data they are supplying within the "add" form, I need a default value inserted into this column. If they are a member of the Marketing role, it should be a 1, if they are a member of the IT role, it should be a 2, etc...
Ideally, this would be done without any knowledge to the user that it is even happening. I would assume that I need to use an "Instead Of" trigger, but I have no idea how to proceed....
Shouldn't be too difficult:
In your app, keep track of the logged-in user and their role.
When your app saves the customer data, make sure it passes the database the role ID as well as the user-entered data (a stored procedure would be ideal here)
When the database processes the supplied data, it saves the role ID into the appropriate column.
this should work provided the rolename-column (or id) is unique in the securityMap-table otherwise the select could return more than one value, maybe you need to select the departmentId differently then.
insert into customer_info(otherdata, departmentId) values('data', (select departmentId from securityMap where rolename = 'userrole'))
Edit:
since you mentioned db_owner maybe this can help you (from http://www.sqlservercentral.com/Forums/Topic411310-338-1.aspx)
WITH CTE_Roles (role_principal_id)
AS
(
SELECT role_principal_id
FROM sys.database_role_members
WHERE member_principal_id = USER_ID()
UNION ALL
SELECT drm.role_principal_id
FROM sys.database_role_members drm
INNER JOIN CTE_Roles CR
ON drm.member_principal_id = CR.role_principal_id
)
SELECT USER_NAME(role_principal_id) RoleName
FROM CTE_Roles
ORDER BY RoleName;
you could join that with the SecurityMap-table to filter out roles like db_owner