SQL join query result issue - sql

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

Related

insert into select from inner join where not exists

I have this SQL Server code. Everything works except it duplicates rows with same RightsId and UserId. The where not exists clause is not working.
Any help is appreciated.
INSERT INTO dbo.UserAccessRights (Id, UserId, RightType, RightsId, CreatedOn, CreatedBy)
SELECT DISTINCT
NEWID(),
#changedUserId,
N'Process ' + #rightsTypeSuffix,
ptm.ProcessInstance_id,
getdate(),
#loggedInUserId
FROM
dbo.ProcessTeamMembers ptm WITH (NOLOCK)
INNER JOIN
dbo.Users u WITH (NOLOCK) ON ptm.TeamMemberProfile_id = u.ProfileID
AND u.Id = #changedUserId
AND ptm.TenantId = #tenantId
INNER JOIN
dbo.ProcessInstances p_i WITH (NOLOCK) ON p_i.Id = ptm.ProcessInstance_id
AND p_i.DeletedOn IS NULL
WHERE
NOT EXISTS (SELECT *
FROM UserAccessRights uar WITH (NOLOCK)
WHERE uar.UserId = #changedUserId
AND uar.RightsId = ptm.ProcessInstance_id)
Your duplicates are probably coming from within the query, rather than from existing rows in the table. Possibly, the problem is that the select distinct isn't doing anything -- because newid() is always unique.
My recommendation is to change the id column to have a default value of newid(). Then you don't need to insert it and the select distinct will work. Absent that, you can fix the query:
INSERT INTO dbo.UserAccessRights (Id, UserId, RightType, RightsId, CreatedOn, CreatedBy)
SELECT DISTINCT NEWID(), #changedUserId, N'Process ' + #rightsTypeSuffix,
ProcessInstance_id, getdate(), #loggedInUserId
FROM (SELECT DISTINCT ptm.ProcessInstance_id
FROM dbo.ProcessTeamMembers ptm WITH (NOLOCK) INNER JOIN
dbo.Users u WITH (NOLOCK)
ON ptm.TeamMemberProfile_id = u.ProfileID AND
u.Id = #changedUserId AND
ptm.TenantId = #tenantId INNER JOIN
dbo.ProcessInstances p_i WITH (NOLOCK)
ON p_i.Id = ptm.ProcessInstance_id AND
p_i.DeletedOn IS NULL
WHERE NOT EXISTS (SELECT 1
FROM UserAccessRights uar WITH (NOLOCK)
WHERE uar.UserId = #changedUserId AND
uar.RightsId = ptm.ProcessInstance_id
)
) t;
Hmmm, as I think about this, perhaps you should be using TOP 1 rather than SELECT DISTINCT. I'm not sure which columns cause the problem on the distinct, but you are inserting the same value in many columns, so more than one row might cause an issue.
Try the "Left Excluding Join" (See Visual Representation of SQL Joins) instead of the WHERE NOT EXISTS clause.
INSERT INTO dbo.UserAccessRights (Id, UserId, RightType, RightsId, CreatedOn, CreatedBy)
SELECT DISTINCT
NEWID(),
#changedUserId,
N'Process ' + #rightsTypeSuffix,
ptm.ProcessInstance_id,
getdate(),
#loggedInUserId
FROM
dbo.ProcessTeamMembers ptm
INNER JOIN
dbo.Users u ON ptm.TeamMemberProfile_id = u.ProfileID
AND u.Id = #changedUserId
AND ptm.TenantId = #tenantId
INNER JOIN
dbo.ProcessInstances p_i ON p_i.Id = ptm.ProcessInstance_id
AND p_i.DeletedOn IS NULL
LEFT JOIN UserAccessRights uar
ON uar.UserId = u.Id
AND uar.RightsId = ptm.ProcessInstance_id
WHERE
uar.Id IS NULL -- Replace with the actual pkey on UserAccessRights if not Id

Optimizing SQL join single column with multiple columns in another table

I have two tables.
common_products
id
product
owner_uid
backup_uid
manager_uid
ss_users
userID
firstName
lastName
email
I want to get a name/email list of all the owners, backups and managers.
I am using the query below, but was wondering if there was a more efficient way to go about querying the tables.
WORKING QUERY:
SELECT DISTINCT email,
( firstName + ' ' + lastName ) AS userFull,
lastName
FROM common_products cp
LEFT OUTER JOIN ss_users u
ON u.userID = cp.owner_uid
UNION
SELECT DISTINCT email,
( firstName + ' ' + lastName ) AS userFull,
lastName
FROM common_products cp
LEFT OUTER JOIN ss_users u
ON u.userID = cp.backup_uid
UNION
SELECT DISTINCT email,
( firstName + ' ' + lastName ) AS userFull,
lastName
FROM common_products cp
LEFT OUTER JOIN ss_users u
ON u.userID = cp.manager_uid
Is there a more optimized way to query the database?
I suspect that this version might be faster:
select u.email, (u.firstName+ ' '+u.lastName) AS userFull, u.lastName
from ss_users u
where exists (select 1 from common_products cp where u.userID = cp.owner_uid) or
exists (select 1 from common_products cp where u.userID = cp.backup_uid) or
exists (select 1 from common_products cp where u.userID = cp.manager_uid);
Then for best performance add three indexes: common_products(owner_uid), common_products(backup_uid), and common_products(manager_uid).
This will eliminate the duplicate elimination (because you are using union) and the exists should be at least as fast as the joins.
I'm going to simplify it, but the JOIN is the important part. I'll leave it to you to tweak the SELECT part.
SELECT DISTINCT owner.email AS owner_email, backup.email AS back_email, manager.email AS man_email
FROM common_product cp LEFT JOIN ss_users owner on owner.userID = cp.owner_uid
LEFT JOIN ss_users backup on backup.userID = cp.backup_uid
LEFT JOIN ss_users manager on manager.userID = cp.manager_uid
Ensure there are indexes on common_products's owner_uid, backup_uid, and manager_uid fields as well as ss_users's userID field and you could improve performance a bit further by including the columns needed on the index.
SELECT DISTINCT
user_owner.email [OwnerEmail],user_owner.firstName + ' ' + user_owner.lastName [OwnerUserFull], user_owner.lastName [OwnerLastName],
user_backup.email [BackupEmail],user_backup.firstName + ' ' + user_backup.lastName [BackupUserFull], user_backup.lastName [BackupLastName],
user_manager.email [ManagerEmail],user_manager.firstName + ' ' + user_manager.lastName [ManagerUserFull], user_manager.lastName [ManagerLastName]
FROM common_products cp
LEFT OUTER JOIN ss_users user_owner ON user_owner.userID = cp.owner_uid
LEFT OUTER JOIN ss_users user_backup ON user_backup.userID = cp.backup_uid
LEFT OUTER JOIN ss_users user_manager ON user_manager.userID = cp.manager_uid
It's been a while since I've practised by SQL fu, but I think this should work:
SELECT DISTINCT email,
(firstName+ ' '+lastName) AS userFull,
lastName
FROM common_products cp
INNER JOIN ss_users u
ON (u.userID = cp.owner_uid OR u.userID = cp.backup_uid OR u.userID = cp.manager_uid)

Better ways to write this SQL Query

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
)

select user doesn't contain a record in other table sql query

I had three tables: sarcuser, sarcusercommittee, sarcallcourse. I need to build a query that brings all the users that don't have a committee (they don't have a record in sarcusercommittee). Here is my current query:
SELECT u.firstname + ' ' + u.lastname AS name, u.dateofbirth, u.gender, LEFT(u.note, 200) AS note, c.name AS coursename
FROM sarcuser AS u INNER JOIN
sarcusercommittee AS uc ON u.id = uc.user_id INNER JOIN
sarcallcourse AS c ON c.id = u.courseid
WHERE ((SELECT COUNT(id) AS Expr1
FROM sarcusercommittee
WHERE (user_id = u.id)) = 0)
ORDER BY name DESC
I guess the problem is in (ON condistion) but don't get it ... any help ?
NOTE : I use visual studio 2010
SELECT u.firstname + ' ' + u.lastname AS name, u.dateofbirth, u.gender, LEFT(u.note, 200) AS note, c.name AS coursename
FROM sarcuser AS u
INNER JOIN sarcallcourse AS c
ON c.id = u.courseid
WHERE u.id NOT IN (
SELECT uc.user_id
FROM sarcusercommittee AS uc
)
ORDER BY name DESC
Firstly you shouldn't inner join onto sarcusercommittee if you dont want rows from it. Seconly I would filter to the users that are not in sarcusercommittee using NOT IN.

Delete statement SQL joins

Can anyone please tell me how to write a delete statement for the following query:
SELECT a.UserID, b.UserEmailAddress
FROM tblUserProgramme AS a LEFT OUTER JOIN
tblUser AS b ON b.UserID = a.UserID LEFT OUTER JOIN
tblWorkGroup AS c ON c.WorkGroupID = b.WorkGroupID
WHERE(a.ProgrammeID = 59) AND (a.UserID NOT IN
(SELECT UserID FROM tblUser AS a WHERE (WorkGroupID IN
(SELECT WorkGroupID FROM tblWorkGroup WHERE
(WorkGroupName LIKE '%Insight%') OR (WorkGroupName LIKE '%Other%')))))
AND (b.UserEmailAddress NOT IN
(SELECT email FROM tmpUsers))
ORDER BY b.UserEmailAddress
SERVER is SQL Server 2005
Query would be
Delete from
(
SELECT a.UserID, b.UserEmailAddress
FROM tblUserProgramme AS a LEFT OUTER JOIN
tblUser AS b ON b.UserID = a.UserID LEFT OUTER JOIN
tblWorkGroup AS c ON c.WorkGroupID = b.WorkGroupID
WHERE(a.ProgrammeID = 59) AND (a.UserID NOT IN
(SELECT UserID FROM tblUser AS a WHERE (WorkGroupID IN
(SELECT WorkGroupID FROM tblWorkGroup WHERE (WorkGroupName LIKE
'%Insight%') OR (WorkGroupName LIKE '%Other%'))))) AND (b.UserEmailAddress NOT IN
(SELECT email FROM tmpUsers))
ORDER BY b.UserEmailAddress
) a
Syntax is DB specific..
For most of tha databases this should work , if you want to delete from tblUserProgramme
DELETE A
FROM tblUserProgramme AS a
.....
In general, in SQL Server, you can delete all records which match a given SQL query as follows, provided your SELECT only returns columns from a single table:
DELETE x
FROM
(
-- Any query which returns data from a single table, that you wish to delete
) x;
Or, using a CTE:
;WITH x as
(
-- Any query which returns data from a single table, that you wish to delete
)
DELETE x;
Thank you all for your quick answers:) There were a quite a few answers right, but had to pick the first one:)
As Joe G Joseph has mentioned,
this is what i did
DELETE a
from dbo.tblUserProgramme a
LEFT OUTER JOIN tblUser b ON b.UserID = a.UserID
LEFT OUTER JOIN tblWorkGroup c ON c.WorkGroupID = b.WorkGroupID
where a.ProgrammeID = 59 AND
a.UserID NOT IN (SELECT UserID FROM tblUser a WHERE a.WorkGroupID IN
(SELECT WorkGroupID FROM tblWorkGroup
WHERE WorkGroupName like '%Insight%' OR WorkGroupName like '%Other%'))
AND b.UserEmailAddress NOT IN(SELECT email FROM tmpUsers)