SQL Server 2012 Query - Foreign Key from Same Table - sql

I have a table named RoleDetails with this structure:
ROLE_ID - PK ,
NAME ,
PARENT_ROLE_ID FK ,
CREATED_BY_ID ,
MODIFIED_BY_ID
The other table is user_details
USER_ID ,
USERNAME ,
FULLNAME
How do I query this table so that in the result set
I get the RoleName, RoleId, ParentRoleId, ParentRoleName, CreatedByName and ModifiedByName.
So far I have tried:
SELECT
[ROLE_ID] AS ID, r.NAME AS [RoleName],
r.PARENT_ROLE_ID AS [ParentRoleID] ,
(SELECT rd.NAME FROM dbo.ROLES rd
WHERE rd.ROLE_ID = r.PARENT_ROLE_ID ) AS [ParentRoleName],
CONCAT(ud.FIRST_NAME, ' ', ud.LAST_name) AS [CreatedByName] ,
CONCAT(u.FIRST_NAME, ' ', u.LAST_name) AS [LastModifiedByName]
FROM
dbo.ROLES r
LEFT OUTER JOIN
user_details u ON r.MODIFIED_BY = u.USER_ID
LEFT OUTER JOIN
dbo.USER_DETAILS ud ON r.CREATED_BY = ud.USER_ID
WHERE
r.ROLE_ID = #iRoleID;

You will need to join the user_detail table twice. Once to get the create user and once to get the modify user.
SELECT rd.Name,
rd.Role_ID,
rd.Parent_role_id,
pr.Name,
ud.userName as CreatedByName,
udm.userName as ModifyByName
FROM RoleDetails as rd
INNER JOIN RoleDetails as pr
ON rd.Parent_Role_Id = pr.Role_id
INNER JOIN User_Detail as ud
on rd.Created_by_id = ud.user_id
INNER JOIN User_Detail as udm
ON rd.Modified_by_user = udm.user_id

Related

replace NOT IN with LEFT JOIN

I've got a table structure like this
[condition]
condition_id, (pk)
question_id (fk)
[option]
condition_id, (fk)
ext_id (fk)
[external]
ext_id, (pk)
inst_id (fk)
[instance]
inst_id, (pk)
keeper_id (fk)
[keeper]
keeper_id, (pk)
org_id
[question]
question_id (pk)
org_id
[localization]
question_id (fk, pk),
org_id (pk),
language (pk)
label
I need to get all questions from question table with localizations (from localization table), that do not exist in condition table for certain ext_id.
My query is
SELECT
q.question_id as q_id,
l.label as q_value
FROM question q
INNER JOIN localization l
ON l.question_id = q.question_id
INNER JOIN external ex
ON ex.ext_id = 'EXTERNAL_ID'
INNER JOIN instance i
ON i.inst_id = ex.inst_id
INNER JOIN keeper k
ON k.keeper_id = i.keeper_id
WHERE q.org_id IN ('*', k.org_id)
AND l.org_id = '*'
AND l.language = 'EN'
AND q.question_id NOT IN (
SELECT
question_id
FROM condition c
INNER JOIN option o
ON o.condition_id = c.condition_id
WHERE o.ext_id = 'EXTERNAL_ID'
)
But how to replace that subquery with LEFT JOIN?
Here is one way
SELECT p.question_id AS q_id,
l.label AS q_value
FROM question q
INNER JOIN localization l
ON l.question_id = q.question_id
INNER JOIN EXTERNAL ex
ON ex.ext_id = 'EXTERNAL_ID'
INNER JOIN instance i
ON i.inst_id = ex.inst_id
INNER JOIN keeper k
ON k.keeper_id = i.keeper_id
LEFT JOIN (select distinct c.question_id
from condition c
JOIN option o
ON o.condition_id = c.condition_id
AND o.ext_id = 'EXTERNAL_ID' ) c
ON c.question_id = q.question_id
WHERE q.org_id IN ( '*', k.org_id )
AND l.org_id = '*'
AND l.language = 'EN'
AND c.question_id IS NULL
I am not a expert in Postgres but I prefer NOT EXISTS to do this
SELECT p.question_id AS q_id,
l.label AS q_value
FROM question q
INNER JOIN localization l
ON l.question_id = q.question_id
INNER JOIN EXTERNAL ex
ON ex.ext_id = 'EXTERNAL_ID'
INNER JOIN instance i
ON i.inst_id = ex.inst_id
INNER JOIN keeper k
ON k.keeper_id = i.keeper_id
WHERE q.org_id IN ( '*', k.org_id )
AND l.org_id = '*'
AND l.language = 'EN'
AND NOT EXISTS (SELECT 1
FROM condition c
INNER JOIN option o
ON o.condition_id = c.condition_id
WHERE o.ext_id = 'EXTERNAL_ID'
AND q.question_id = c.question_id)

Too many results in query

I'm fetching some data from our database in MSSQL. Out of this data I want to determine who created the client entry and who took the first payment from this client.
There can be many payment entries for a client on a single booking/enquiry and at the moment, my query shows results for each payment. How can I limit the output to only show the first payment entry?
My query:
SELECT
c.FirstName,
c.LastName,
c.PostalCode,
o.OriginOfEnquiry,
s.SuperOriginName,
c.DateOfCreation,
DATEDIFF(day, c.DateOfCreation, p.DateOfCreation) AS DaysToPayment,
pc.PackageName,
CONCAT(u.FirstName, ' ', u.LastName) AS CreateUser,
(SELECT CONCAT(u.FirstName, ' ', u.LastName)
WHERE u.UserID = p.UserID ) AS PaymentUser
FROM tblBookings b
INNER JOIN tblPayments p
ON b.BookingID = p.BookingID
INNER JOIN tblEnquiries e
ON e.EnquiryID = b.EnquiryID
INNER JOIN tblCustomers c
ON c.CustomerID = e.CustomerID
INNER JOIN tblOrigins o
ON o.OriginID = e.OriginID
INNER JOIN tblSuperOrigins s
ON s.SuperOriginID = o.SuperOriginID
INNER JOIN tblBookingPackages bp
ON bp.bookingID = p.BookingID
INNER JOIN tblPackages pc
ON pc.PackageID = bp.packageID
INNER JOIN tblUsers u
ON u.UserID = c.UserID
WHERE c.DateOfCreation >= '2016-06-01' AND c.DateOfCreation < '2016-06-30'
AND p.PaymentStatusID IN (1,2)
AND e.CustomerID = c.CustomerID
AND p.DeleteMark != 1
AND c.DeleteMark != 1
AND b.DeleteMark != 1
;
I tried adding a "TOP 1" to the nested select statement for PaymentUser, but it made no difference.
you can use cross apply with top 1:
FROM tblBookings b
cross apply
(select top 1 * from tblPayments p where b.BookingID = p.BookingID) as p
Instead of table tblPayments specify sub-query like this:
(SELECT TOP 1 BookingID, UserID, DateOfCreation
FROM tblPayments
WHERE DeleteMark != 1
AND PaymentStatusID IN (1,2)
ORDER BY DateOfCreation) as p
I'm assuming that tblPayments has a primary key column ID. If it is true, you can use this statment:
FROM tblBookings b
INNER JOIN tblPayments p ON p.ID = (
SELECT TOP 1 ID
FROM tblPayments
WHERE BookingID = b.BookingID
AND DeleteMark != 1
AND PaymentStatusID IN (1,2)
ORDER BY DateOfCreation)

SQL join query result issue

I have two tables one is Friends table and other table is user profile table (all user related information e.g. firstname, lastname etc) both has relation among them
Friend table (It has two entries for every user for e.g. the first two rows)
Now i want to display names of users from above table which will look like below
so in the output i want to remove duplicates which is not working for me
my query
select distinct u.FirstName + ' ' + u.LastName As UserName,
(select distinct firstname + ' ' + lastname from UserProfiles where id = uw.friendid) as FriendName
from UserFriends as uw left join userprofiles as u
on u.id = uw.userid
You need to join UserProfiles twice on UserFriends since there are two columns are dependent on it.
SELECT a.ID,
f.FirstName + ' ' + f.LastName FriendName,
u.FirstName + ' ' + u.LastName UserName
FROM UserFriends a
INNER JOIN UserProfiles f
ON a.FriendID = f.ID
INNER JOIN UserProfiles u
ON a.UserID = u.ID
INNER JOIN UserFriends dup
ON a.FriendID = dup.UserID
AND dup.FriendID = a.UserID
AND a.ID > dup.ID
SQLFiddle Demo
I would suggest that you have to use CTE to eliminate the duplicates from the beggining(that can be done by self joining the table). I have managed to reproduce your scenario, so if you adjust the query a bit, you will be able to obtain the desired result
with cte as
(select
t1.id as a_id
,t1.friendID as a_friendID
,t1.userID as a_userID
,t2.id as b_id
,t2.friendID as b_friendID
,t2.userID as b_userID
from #temp t1
left join #user t2 on t1.id+1=t2.id
),
cte2 as
select
a_id
,a_userID
,a_friendID
from cte t1
where a_friendID = (select b_friendID from cte t2 where t2.b_id= t1.b_id-1)
)
select firstname+ ' '+lastname as FriendName
,firstname+ ' '+lastname as UserName
from cte2 uw
left join UserProfiles u on uw.a_userID=u.ID and uw.a_friendID=u.id

How to add a subquery to return count of related rows

I have a working SELECT that returns info on each company (i.e. subscriber). Certain descriptive data is returned from inner joins on "code" tables. My problem is how to add a new column to the result which is a count of the number of users belonging to each subscriber. SubscriberID in the user table is a foreign key:
ALTER TABLE dbo.UserInfo WITH CHECK ADD CONSTRAINT FK_UserInfo_SubscriberID
FOREIGN KEY(SubscriberID) REFERENCES dbo.Subscriber (SubscriberID)
ON UPDATE CASCADE
ON DELETE CASCADE
I added the LEFT OUTER JOIN below and the GROUP BY but I cannot figure out why the parser complains that U.SubscriberID is an invalid column name).
SELECT SubscriberID
,SubscriberName
,DaysUntilExpired
,SubscriptionStatus SubscriptionStatusCode
, C.Description SubscriptionStatus
,U.NumberUsers
FROM dbo.Subscriber S
JOIN dbo.CodeValue C ON S.SubscriptionStatus = C.Value
JOIN dbo.CodeNamespace N ON N.ID = C.CodeNamespaceID AND N.Name = 'SubscriptionStatus'
JOIN dbo.CodeValue V ON S.NotificationStatus = V.Value
JOIN dbo.CodeNamespace X ON X.ID = V.CodeNamespaceID AND X.Name = 'NotificationStatus'
LEFT OUTER JOIN (SELECT Count(*) AS NumberUsers FROM dbo.UserInfo) AS U
ON S.SubscriberID = U.SubscriberID
GROUP BY
S.SubscriberID
,SubscriberName
,DaysUntilExpired
,S.SubscriptionStatus
,SubscriptionStatus
You are probably looking for the following. You need to inline the subquery
SELECT SubscriberID
,SubscriberName
,DaysUntilExpired
,SubscriptionStatus SubscriptionStatusCode
, C.Description SubscriptionStatus
,(SELECT Count(*) AS NumberUsers FROM dbo.UserInfo where SubscriberID = S.SubscriberID) AS NumberUsers
FROM dbo.Subscriber S
JOIN dbo.CodeValue C ON S.SubscriptionStatus = C.Value
JOIN dbo.CodeNamespace N ON N.ID = C.CodeNamespaceID AND N.Name = 'SubscriptionStatus'
JOIN dbo.CodeValue V ON S.NotificationStatus = V.Value
JOIN dbo.CodeNamespace X ON X.ID = V.CodeNamespaceID AND X.Name = 'NotificationStatus'
GROUP BY
S.SubscriberID
,SubscriberName
,DaysUntilExpired
,S.SubscriptionStatus
,SubscriptionStatus
Sql complains because your LEFT OUTER JOIN subquery does not include SubscriberId in column list (and in a group by clause since you have a COUNT aggregate), so it can't make the join on this column.
You should do:
LEFT OUTER JOIN (SELECT SubscriberID , Count(*) AS NumberUsers FROM dbo.UserInfo GROUP BY SubscriberID ) AS U
ON S.SubscriberID = U.SubscriberID

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