How to build permissions for logged user? - sql

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.

Related

Retrieve the most recent person record added to an account

I am trying to build a table of Contact IDs (Primary Keys) of the most recently created records assigned to each Account of a certain type in our Salesforce org.
Working in Salesforce Marketing Cloud, I'm trying to build a sample list that I can setup to update automatically so the records I'm testing against are never stale. I only need one example from each account to do my testing. Since I want to make sure the record isn't stale, I want to select the most recent record assigned to each Account.
Every Contact is assigned to one and only one Account. The Account ID lives as a foreign key on the Contact Record. The created date of the Contact is also a field on the Contact record.
The Sample list needs to contain the email address, ContactID, and the name of the Management Company, which lives on the Account record.
I figured doing a directional JOIN toward the Account table would do the trick, but that didn't work. I figure that's because there's nothing distinguishing which record to pick.
This is what I've got for code, which is pretty useless...
SELECT
C.Email AS Email,
C.Id AS Id18,
C.AccountID AS AccountID,
A.Management_Company AS ManagementCompany
FROM
ENT.Contact_Salesforce_DE AS C
RIGHT JOIN ENT.Account_Salesforce_DE AS A ON C.AccountID = A.Id
WHERE
A.RecordTypeId = '1234567890ABCDEFGH' AND
A.Management_Company IS NOT NULL AND
C.Email IS NOT NULL
The syntax checks out, but I get a system error every time I run it.
Marketing Cloud runs on an older version of SQL Server, so some more recent query functions won't always work.
And yes, I'm a relative noob to SQL. Won't surprise me if this has a really simple solution, but I couldn't find another entry describing the solution, so...
If I followed you correctly, you want to pull out the latest contact associated with each account.
On database servers that do not support window function (which seems to be the case of your RDBMS), one typical solution is to add a special condition to the JOIN. This NOT EXISTS condition uses a subquery to ensure that the record being picked in the child table is the most recent one (in other words : there is no child record with a highest creation date than the one being joined) :
SELECT
c.Email AS Email,
c.Id AS Id18,
c.AccountID AS AccountID
FROM
ENT.Account_Salesforce_DE AS a
INNER JOIN ENT.Contact_Salesforce_DE AS c
ON c.AccountID = a.Id
AND c.email IS NOT NULL
AND NOT EXISTS (
SELECT 1
FROM ENT.Contact_Salesforce_DE AS c1
WHERE
c1.email IS NOT NULL
AND c1.AccountID = a.Id
AND c1.CreatedDate > c.CreatedDate
)
WHERE
A.RecordTypeId = '1234567890ABCDEFGH'
AND A.Management_Company IS NOT NULL

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.

Handling table with multiple child entities with Discriminators

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.

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

SQL Stored procedure

I have 3 tables:
tbl_Image from which a list of all images will be obtained
A user table from which User ID will be obtained
and an association table of Image and Member called tbl_MemberAssociation.
My work flow is that a user can upload image and this will be stored in to image table. Then all users can view this image and select one of three choice provided along with the image. If user selects an option it will be added to Association table. No user can watch same image more than once. So multiple entries will not be there.
Now I want to find the % of match by getting the list of members choose the same option and different option corresponding to all common images for which they have provided their option.
I.e. say if 3 users say A, B and C view an image of tajmahal. If A and B opted beautiful as choice and C as "Not Good ". For another image say Indian Flag A B and C opted same as Salute. Then for User A: B have 100 % match (since they selected same option both times). For A : C have 50% match one among 2 same.
So this is my scenario, in which I have to find all matched corresponding to currently logged in User.
Please help me.... I am totally disturbed with this procedure.
I have made some assumptions about the actual structure of your tables, but if I understand what you are looking for then I think this query will get the results you are wanting. You may have to make a few modifications to match your table structures.
SELECT
matches.UserName,
CAST(matches.SameRatings AS FLOAT) / CAST(ratings.UserRatingCount AS FLOAT) AS MatchPercent
FROM
tbl_User
CROSS APPLY
(
SELECT
COUNT(*) UserRatingCount
FROM
tbl_MemberAssociation
WHERE
UserId = tbl_User.UserId
) ratings
CROSS APPLY
(
SELECT
u1.UserId,
u1.UserName,
COUNT(*) AS SameRatings
FROM
tbl_MemberAssociation ma
INNER JOIN
tbl_MemberAssociation ma1
ON
ma.ImageId = ma1.ImageId
AND ma.Rating = ma1.Rating
AND ma.UserId <> ma1.UserId
INNER JOIN
tbl_User u1
ON
ma1.userId = u1.UserId
WHERE
ma.UserId = tbl_User.UserId
GROUP BY
u1.UserId,
u1.UserName
) matches
WHERE
tbl_User.UserId = #UserId
ORDER BY
MatchPercent DESC
#UserId could be passed as an input to the stored procedure.
The 1st CROSS APPLY "ratings" is getting a count of for the total number of ratings for the logged in user.
The 2nd CROSS APPLY "matches" is getting a count of the number of like ratings for the other users in the database.
The result set uses the counts calculated by the two CROSS APPLY queries to compute the match percentage between the logged in user and the other users who have rated the same images as the logged in user.