Better ways to write this SQL Query - sql

I have the below table structure
Users (PK - UserId)
System (PK - SystemId)
SystemRoles (PK-SystemRoleId, FK - SystemId)
UserRoles (PK-UserId & SystemRoleId, FK-SystemRoleId, FK-UserId)
Users can have access to different Systems and one System can have different SystemRoles defined.
Now, I need to delete Users who have SystemRoles assigned to them ONLY for a specific System(s). If they have SystemRoles defined for other Systems, they should not be deleted.
I have come up the below query to identify the records that are eligible for delete but think this can surely be optimized. Any suggestions?
SELECT U.*
FROM
(
SELECT
distinct UR.UserID
FROM
dbo.UserRole UR
INNER JOIN dbo.SystemRole SR ON (SR.SystemRoleID = UR.SystemRoleID)
INNER JOIN dbo.[System] S ON (S.SystemID = SR.SystemID)
WHERE
S.SystemName = 'ABC' OR S.SystemName = 'XYZ'
) T
INNER JOIN dbo.[User] U ON (U.UserID = T.UserID)
WHERE T.UserID NOT IN
(
select
distinct UR.UserID
from
dbo.[UserRole] UR
INNER JOIN dbo.SystemRole SR ON (SR.SystemRoleID = UR.SystemRoleID)
INNER JOIN dbo.[System] S ON (S.SystemID = SR.SystemID)
WHERE
S.SystemName <> 'ABC'
AND S.SystemName <> 'XYZ'
)

something like this?
select userid from (
SELECT
UR.UserID,
max(case when (S.SystemName = 'ABC' OR S.SystemName = 'XYZ')
then 1 else 0 end) as kill,
max(case when (S.SystemName <> 'ABC' AND S.SystemName <> 'XYZ')
then 1 else 0 end) as keep
FROM
dbo.UserRole UR
INNER JOIN dbo.SystemRole SR ON (SR.SystemRoleID = UR.SystemRoleID)
INNER JOIN dbo.[System] S ON (S.SystemID = SR.SystemID)
group by UR.UserID
) u where kill = 1 and keep = 0

This sort of structure will get you the records you need.
select yourfields -- or delete
from userroles
where userid in
(select userid
from userroles join etc
where system.name = the one you want
except
select userid
from userroles join etc
where system.name <> the one you want
)

Related

INSERT INTO not working with my select

I need to copy some data from one table to another:
There is a table that has the correct date (AUDITLOG), column TIME but I need to put it in the USER table, column USERS_DATE and associate with the correct user...
The SELECT returns the correct data by itself, I'm having issue using the SELECT INTO statement. My hacked up code below:
INSERT INTO users (USERS_DATE) WHERE USERID=U.USERID
(SELECT U.USERID,
javaTimeStampToDate (L.TIME)
AS "Last Login"
FROM COMPANY C,
USERS U,
AUDITMAP M,
AUDITLOG L
WHERE C.COMPANYID = U.COMPANYID
AND U.USERID = M.ROWID
AND M.AUDITID = L.AUDITID
AND C.APPLICATION = 'A'
AND L.NOTES LIKE '%went inactive%'
AND U.STATUS = 0);
Try with the below query for sql server.
I think you need an update query. Also change your commas with JOIN condition.
UPDATE U
SET U.USERS_DATE=L.TIME
FROM COMPANY C
JOIN USERS U ON C.COMPANYID = U.COMPANYID
JOIN AUDITMAP M ON U.USERID = M.ROWID
JOIN AUDITLOG L ON M.AUDITID = L.AUDITID
WHERE C.APPLICATION = 'A'
AND L.NOTES LIKE '%went inactive%'
AND U.STATUS = 0
use below query for oracle,
MERGE INTO USERS U
USING
(
SELECT M.ROWID,L.Time
FROM AUDITMAP M
JOIN AUDITLOG L ON M.AUDITID = L.AUDITID
WHERE L.NOTES LIKE '%went inactive%'
) Au ON (U.USERID = Au.ROWID)
WHEN MATCHED THEN UPDATE
SET U.USERS_DATE = Au.TIME
WHERE U.STATUS = 0 AND EXISTS (select 1
from COMPANY c
where .COMPANYID = U.COMPANYID AND C.APPLICATION = 'A')

SQL Query to check if joining record exists

I have 2 tables - User table (tblUsers) and Logs table (tblLogs).
The User table contains - UserID and UserName.
The Logs table contains - UserID, ApplicationID, ApplicationName, LogonDateTime
I want to select all the Users and find if they have accessed a particular application (for example ApplicationID = 3)
Output expected
UserID, UserName, Status
Status - If he has visited the applicationID = 3 or not.
Since you are missing a third table which contain all the applications available ( i guess it's [tblApplications] ), the sql would be:
SELECT
U.UserID
, U.UserName
, (
CASE WHEN L.ApplicationID IS NOT NULL
THEN '1'
ELSE '0'
END
) AS Status
FROM tblUsers AS U, tblApplications AS A
LEFT OUTER JOIN tblLogs AS L
ON A.ID = L.ApplicationID
WHERE A.ID = '3'
Use a CASE expression to check the status.
Query
select t1.UserId, t1.UserName,
max(case when t1.UserId in
(select UserId from tblLogs where ApplicationID = 3) then 'Visited'
else 'Not Visited' end) as `status`
from tblUsers t1
left join tblLogs t2
on t1.UserID = t2.UserID
group by t1.UserId, t1.UserName;
SQl Fiddle Demo
I hope this query give you the direction of thought as to what you exact requirement is:
SELECT u.UserID,
u.UserName,
(SELECT (CASE
WHEN COUNT(*) > 0 THEN
'VISITED'
ELSE
NULL
END)
FROM tblLogs l
WHERE u.UserId = l.UserId
AND l.ApplicationID = '3')
AS status
FROM tblUsers u
Note that based on the DB that you use, the group by on UserName and ApplicationName might be optional.

How to eliminate 'The multi-part identifier "" could not be bound' error?

I have this query, it's supposed to return results of non validated accounts in a database, that were created after a certain date. I keep getting this error and I'm not sure how to eliminate it. Here is the query:
select count(*) (nolock)
from dbo.[User]
where ID is not null
and UserStatusID!=2
and CreateDateTime>='5/1/2012'
and not exists (select userid from dbo.UserValidation where dbo.[User].UserID=dbo.UserValidation.UserID)
It errors out on the "where dbo.[User].UserID=dbo.UserValidation.UserID" What am I doing wrong here?
Try aliasing the tables:
select count(*) (nolock)
from dbo.[User] u
where ID is not null
and UserStatusID != 2
and CreateDateTime >= '5/1/2012'
and not exists (select uv.userid from dbo.UserValidation uv where u.UserID = uv.UserID)
Without the schema:
select count(*) (nolock)
from [User] u
where ID is not null
and UserStatusID != 2
and CreateDateTime >= '5/1/2012'
and not exists (select uv.userid from UserValidation uv where u.UserID = uv.UserID)
While doing a JOIN it's always better to explicitly qualify all the columns in query like below.
select count(u.userid)
from [User] u
where u.ID is not null
and u.UserStatusID != 2
and u.CreateDateTime >= '5/1/2012'
and not exists
(
select uv.userid
from UserValidation uv
where uv.UserID = u.UserID
)

SQL - left join generate duplicates

I have code to select some applications but LEFT JOIN is creating duplicates.
Question: How to get rid of duplicates generated by
LEFT JOIN
attachments as att
ON
(a.ssn = att.ssn AND att.doc_type = 'id_copy' AND att.source = 'cpt3')
My Work:
I am considering SELECT DISTINCT or GROUP BY but, can't figure out where to put them.
This is the query:
SELECT
a.*, c.code, l.who, l.locked_time, att.id AS attnew,
( SELECT
COUNT(*)
FROM
applications as a2
WHERE
a2.approved = 'Y'
AND
a2.paid = 'Y'
AND
a2.paid_back = 'Y'
AND
a2.ssn = a.ssn
) AS previous_apps
FROM
applications as a
LEFT JOIN
locked_by as l
USING(id)
LEFT JOIN
campaign_codes as c
ON
c.id = a.campaign
LEFT JOIN
attachments as att
ON
(a.ssn = att.ssn AND att.doc_type = 'id_copy' AND att.source = 'cpt3')
WHERE
a.closed='N'
AND
a.paid = 'N'
ORDER BY
a.arrived_date
DESC
Use GROUP BY
to avoid duplicates. In your case:
...
WHERE
a.closed='N'
AND
a.paid = 'N'
GROUP BY
a.id
ORDER BY
a.arrived_date
DESC
If you want to make an one to one relation to avoid duplicates and att.id is the same for each att.ssn or you need only one (MAX,MIN,..ANY?) att.id. Try this:
LEFT JOIN
(SELECT ssn,
MAX(id) as id,
FROM attachments
WHERE doc_type = 'id_copy' AND source = 'cpt3'
GROUP BY ssn
)as att
ON
(a.ssn = att.ssn)

SQL SELECT statement with users, roles and rights

Lets say that I have tables:
Users
Users_in_Roles
Roles
Rights_in_Roles
Rights
Keys are standard( UserFk, RoleFk, RightFk)
The question is: how to get all users that are in role with right X (id = 100)
I Have no idea how to touch this problem. Please help and sorry for my english.
SELECT [dbo].[System_Users].[Id]
,[UserName]
,[FirstName]
,[LastName]
,[Email]
,RoleFk
,[dbo].[System_Roles].Name
FROM [dbo].[System_Users]
INNER JOIN [dbo].[System_Roles_System_Users]
ON [dbo].[System_Roles_System_Users].UserFk = [dbo].[System_Users].Id
INNER JOIN [dbo].[System_Roles]
ON [dbo].[System_Roles].Id = [dbo].[System_Roles_System_Users].RoleFk
WHERE ?
I tryied sth like that, could you tell me what iw wrong?
SELECT
DISTINCT System_Users.Id,
System_Users.FullName
FROM System_Users
INNER JOIN Dict_Rights_System_Users
ON System_Users.Id = Dict_Rights_System_Users.UserFk
INNER JOIN System_Roles_System_Users
ON System_Roles_System_Users.UserFk = System_Users.Id
WHERE
RightFk = 136
OR
136 IN (SELECT Dict_Rights_System_Roles.RightFk FROM Dict_Rights_System_Roles WHERE
Dict_Rights_System_Roles.RoleFk = System_Roles_System_Users.RoleFk)
ORDER BY System_Users.FullName ASC
You will need to JOIN the tables on the key relationships. The basic structure will be:
select u.Id,
u.UserName,
u.FirstName,
u.LastName,
u.Email,
r.RoleFk,
r.Name RoleName,
rt.Name RightName
from users u
inner join users_in_roles ur
on u.id = ur.userfk
inner join roles r
on ur.rolefk = r.id
inner join rights_in_roles rr
on r.rolefk = rr.rolefk
inner join rights rt
on rr.rightfk = rt.id
where rt.id = 100
If you need help learning JOIN syntax here is a great reference:
A Visual Explanation of SQL Joins
You can try with this:
SELECT *
FROM Users u
WHERE EXISTS (
SELECT ur.RoleFk
FROM Users_in_Roles ur
WHERE u.UserPk = ur.UserFk
AND EXISTS
(
SELECT 1
FROM Rights_in_Roles rr
WHERE rr.RoleFk = ur.RoleFk
AND rr.RightFk = 100
)
)
OR EXISTS (
SELECT 1
FROM Users_Rights uri
WHERE u.UserPk = uri.UserFk
AND uri.RightFk = 100
)
Note that the above query doesn't return RoleFk and Name for the role.
Another approach would be:
SELECT u.Id
,u.UserName
,u.FirstName
,u.LastName
,u.Email
,rr.RoleFk
,r.Name
FROM Users u
-- get users that are in role that has right
LEFT JOIN
Users_in_Roles ur ON
ur.UserFk = u.UserPk
LEFT JOIN
Rights_in_Roles rr ON
rr.RoleFk = ur.RoleFk
AND rr.RightFk = 100
LEFT JOIN
Rights r ON
r.RolePk = rr.RoleFk
-- get users that have a right granted to them directly
LEFT JOIN
Users_Rights uri ON
u.UserPk = uri.UserFk
AND uri.RightFk = 100
WHERE rr.RoleFk IS NOT NULL OR uri.UserFk IS NOT NULL