How to place an ORDER BY clause in SQL between UNIONS - sql

I want to implement simple SQL query that will return a sorted list. The problem is that I get syntax errors for placing the ORDER BY clause anywhere I put it.
SELECT
fr.FunctionRoleID, fr.FunctionRoleInternalName
FROM
users u
JOIN
UserRoles ur ON ur.UserID = u.UserID
JOIN
Roles_FunctionRoles rfr ON rfr.RoleID = ur.RoleID
JOIN
FunctionRoles fr ON fr.FunctionRoleID = rfr.FunctionRoleID
WHERE
u.UserName = #UserName
AND u.Active = 1
UNION
SELECT
fr.FunctionRoleID, fr.FunctionRoleInternalName
FROM
Roles r
JOIN
Roles_FunctionRoles rfr ON rfr.RoleID = r.RoleID
JOIN
FunctionRoles fr ON fr.FunctionRoleID = rfr.FunctionRoleID
WHERE
r.RoleName = 'Authenticated Users'
AND #UserName IS NOT NULL
AND LEN(#UserName) > 0
What I want to insert:
ORDER BY fr.DisplayName ASC
EDIT
If I create a subquery using
SELECT *
FROM
(
[my initial query]
)
ORDER BY
[COLUMN NAME] ASC
I get the following error message:
Incorrect syntax near 'ORDER'. Expected 'AS', 'ID' or 'QUOTED_id'

In most databases, you can only place an order by at the end of a union.
Because the union abstracts away individual table aliases, you only have to list the column name. So omit the fr. :
ORDER BY DisplayName

The ORDER BY clause needs to be placed after the last SELECT statement of the Union.

select * from(
*what you have there*
) as foo
order by DisplayName ASC
I'm not in front of an IDE so the syntax may be off a bit but that's the idea.
e: yeah, figured I'd jack up the syntax...alias added :)

Your not selecting DisplayName so you cannot use it to ORDER BY a set derived from a UNION. If you want to order by it and omit it from the results;
;WITH T (FunctionRoleID, FunctionRoleInternalName, DisplayName) AS (
SELECT
fr.FunctionRoleID, fr.FunctionRoleInternalName, fr.DisplayName
FROM users u
JOIN UserRoles ur ON ur.UserID = u.UserID
JOIN Roles_FunctionRoles rfr ON rfr.RoleID = ur.RoleID
JOIN FunctionRoles fr ON fr.FunctionRoleID = rfr.FunctionRoleID
WHERE
u.UserName = #UserName
AND
u.Active = 1
UNION
SELECT
fr.FunctionRoleID, fr.FunctionRoleInternalName, fr.DisplayName
FROM
Roles r
JOIN Roles_FunctionRoles rfr ON rfr.RoleID = r.RoleID
JOIN FunctionRoles fr ON fr.FunctionRoleID = rfr.FunctionRoleID
WHERE
r.RoleName = 'Authenticated Users'
and #UserName is not null and LEN(#UserName) > 0
)
SELECT
FunctionRoleID, FunctionRoleInternalName
FROM T
ORDER BY DisplayName

Try
SELECT * FROM (
SELECT
fr.FunctionRoleID, fr.FunctionRoleInternalName
FROM
users u
JOIN UserRoles ur ON ur.UserID = u.UserID
JOIN Roles_FunctionRoles rfr ON rfr.RoleID = ur.RoleID
JOIN FunctionRoles fr ON fr.FunctionRoleID = rfr.FunctionRoleID
WHERE
u.UserName = #UserName
AND
u.Active = 1
UNION
SELECT
fr.FunctionRoleID, fr.FunctionRoleInternalName
FROM
Roles r
JOIN Roles_FunctionRoles rfr ON rfr.RoleID = r.RoleID
JOIN FunctionRoles fr ON fr.FunctionRoleID = rfr.FunctionRoleID
WHERE
r.RoleName = 'Authenticated Users'
and #UserName is not null and LEN(#UserName) > 0 ) a
ORDER BY a.FunctionRoleInternalName ASC
Basically, you are selecting against the result of the UNION and then performing the ORDER BY...note that I use "FunctionRoleInternalName"...you can change that to "DiaplayName" only of you use that as a column ALIAS in the UNION queries...e.g. "FunctionRoleInternalName AS DisplayName"

For UNION, ORDER BY goes at the end and applies to the combined result of both queries; you can't order by a column that is not selected by both queries in the union.
what you need to do is select fr.DisplayName in both queries; then you can order by it.
If you don't want the display name to be one of the output columns, nest the whole thing in an outer query that retrieves just the columns you want.

Related

How do I find out which users with a specific RoleID that's not been active within a time interval?

This query down below will tell me how many non-active users there's been during a timeframe.
USE Database
SELECT u.*
FROM [dbo].[tbl_Users] u
WHERE NOT EXISTS (SELECT 1
FROM [dbo].[CaseTable] ct
WHERE c.tUserID = u.UserID AND ct.CreationDate between '2019-01-01' and '2019-12-31'
);
And this query below will tell me the users that have the specific role id I'm looking for.
Use Database;
SELECT UserID, DepartmentID, RoleId
FROM tbl_UsersBelongsTo
WHERE RoleID=6
How can I integrate both queries and essentially get what I'm looking for? I presume it's with a JOIN clause but how??
I think you just want join or additional exists:
SELECT u.*
FROM [dbo].[tbl_Users] u
WHERE NOT EXISTS (SELECT 1
FROM [dbo].[CaseTable] ct
WHERE ct.tUserID = u.UserID AND
ct.CreationDate between '2019-01-01' and '2019-12-31'
) AND
EXISTS (SELECT 1
FROM tbl_UsersBelongsTo ubt
WHERE ubt.RoleID = 6 AND ubt.userId = u.userId
);
Please try to use an inner join like below:
SELECT u.*
FROM [dbo].[tbl_Users] u
INNER JOIN
(
SELECT UserID
FROM tbl_UsersBelongsTo
WHERE RoleID=6
) x ON u.UserID = x.UserID
WHERE NOT EXISTS (SELECT 1
FROM [dbo].[CaseTable] ct
WHERE c.tUserID = u.UserID AND ct.CreationDate between '2019-01-01' and '2019-12-31'
);
You can read more about JOINS here.
If I understood the question correctly - you are using 2 different databases and the name of the 2nd database is pisacara. It is possible to join tables from different databases in SQL Server as long as as those databases are on the same server and you use the same credentials for both databases.
Assuming that tbl_Users table has a UserID field as well, the query would look something like this:
SELECT u.*
FROM [1st_database_name].[dbo].[tbl_Users] u
INNER JOIN [piscara].[dbo].[tbl_UsersBelongsTo] a
ON u.UserID = a.UserID
WHERE NOT EXISTS (SELECT 1
FROM [1st_database_name].[dbo].[CaseTable] ct
WHERE c.tUserID = u.UserID
AND ct.CreationDate BETWEEN'2019-01-01' AND'2019-12-31'
)
AND a.RoleID=6;
You can also try putting the 2nd query in the WHERE clause, as a sub-query, like so:
SELECT u.*
FROM [1st_database_name].[dbo].[tbl_Users] u
WHERE NOT EXISTS (SELECT 1
FROM [1st_database_name].[dbo].[CaseTable] ct
WHERE c.tUserID = u.UserID
AND ct.CreationDate BETWEEN'2019-01-01' AND'2019-12-31'
)
AND u.UserID IN (SELECT UserID
FROM [piscara].[dbo].[tbl_UsersBelongsTo]
WHERE RoleID=6);

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 Subquery column equals operation

I am trying to do a SQL query for user with certain permission enabled flag. I know, I can do this:
select u.ID, u.Name,
(select p.Value
from Permissions p
where p.UserID = u.ID AND p.Key = 'CanEdit') as IsPermissionEnabled
from Users u
But it's not exactly what I need, can I do something like this:
select u.ID, u.Name,
((select p.Value
from Permissions p
where p.UserID = u.ID AND p.Key = 'CanEdit') = 'True')
as IsPermissionEnabled
from Users u
It didn't work for me. So, how to change my query to make it work?
Surely you should just join to the table to get p.Value.
Then you can do with it whatever you like:
SELECT
u.ID,
u.Name,
p.Value as IsPermissionEnabled
FROM Users u
LEFT OUTER JOIN Permissions p
ON p.UserID = u.ID
AND p.Key = 'CanEdit';
Try this query
select u.ID, u.Name, case when p.value>0 then 'True' else '' end
as IsPermissionEnabled
from Users u
left join permission p on p.UserID = u.ID and p.key='CanEdit'
In SQL Server, you need an explicit case statement. So, you can write the query as:
select u.ID, u.Name,
(case when (select p.Value
from Permissions p
where p.UserID = u.ID AND p.Key = 'CanEdit'
) = 'True'
then 1 else 0
end) as IsPermissionEnabled
from Users u;
A join ( inner or left) with a Case can be used to return the desired data with IsPermissionEnabled. Assuming intent is to treat IsPermissionEnabled as boolean, the case statement can set it to a bit value of 0 or 1 as below.
select u.USERID , u.Username, IsPermissionEnabled = case p.[Key] when 'CanEdit' then 1 else 0 end from [Permissions] p inner join [User] u on u.USERID = p.userid

How to simplify a query between Many to Many Relationship

I was wondering how to simplify this query, here(http://sqlfiddle.com/#!3/2789c/4) you have the complete example
SELECT distinct (R.[roleId])
FROM [Role] R
LEFT JOIN [userRole] U ON R.[roleId] = U.[roleId]
WHERE R.RoleID NOT IN(
SELECT [roleId]
from [dbo].[userRole]
WHERE userId = 2)
I want to get all the roles that are not assigned to an specific user. I think the inner select could be erase.
Update 1
After your great help, I could use only one SELECT http://sqlfiddle.com/#!3/2789c/87
SELECT R.[roleID]
FROM [Role] R
LEFT JOIN [userRole] U
ON R.[roleID] = U.[roleID] AND U.userId = #userID
WHERE U.userId IS NULL
As simple as it gets:
select roleId
from Role
except
select roleId
from userRole
where userId = 2
SELECT R.roleId
FROM [Role] R
LEFT JOIN [userRole] U ON R.roleId = U.roleId
group by r.roleId
having sum(case when U.userId = 2 then 1 else 0 end) = 0
SQLFiddle demo
You can also try this
Select distinct role.roleID from role , userrole
except
select roleId from userrole where userID=2
OR
SELECT R.roleId
FROM [Role] R
LEFT JOIN [userRole] U ON R.roleId = U.roleId
except
select roleId from userrole where userID=2

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