Are both queries are same ?
Do both return the same result ?
1)
IF EXISTS(
SELECT
1
FROM
Users u
WHERE
u.UPIN = #AttendingDoctorID)
BEGIN
SELECT
u.UserId, 1
FROM
Users u WITH(nolock)
WHERE
u.UPIN = #AttendingDoctorID
END ELSE BEGIN
SELECT
u.UserId,
1
FROM
Users u (nolock)
WHERE
u.FirstName = #AttendingDoctorFirstName AND
u.LastName = #AttendingDoctorLastName
END
2)
SELECT
u.UserId, 1
FROM
Users u (nolock)
WHERE
(u.UPIN = #AttendingDoctorID)
OR
(u.FirstName = #AttendingDoctorFirstName AND
u.LastName = #AttendingDoctorLastName)
They are not the same.
The 2nd returns data for both conditions.
The 1st one tests first and applies only one condition
They're not semantically the same. The second query will possibly return records that fulfill both predicates (u.UPIN = #AttendingDoctorID) and (u.FirstName = #AttendingDoctorFirstName AND u.LastName = #AttendingDoctorLastName).
Whether or not this will ever occur depends on your data.
Assuming you're running under the default transaction isolation level, you also need to be aware that:
IF EXISTS(
SELECT
1
FROM
Users u
WHERE
u.UPIN = #AttendingDoctorID) --<-- Query 1
BEGIN
SELECT
u.UserId, 1
FROM
Users u WITH(nolock)
WHERE
u.UPIN = #AttendingDoctorID --<-- Query 2
END ELSE BEGIN
SELECT
u.UserId,
1
FROM
Users u (nolock)
WHERE
u.FirstName = #AttendingDoctorFirstName AND
u.LastName = #AttendingDoctorLastName
END
Another transaction might update Users between query 1 executing and query 2 executing, and so you might get an empty result set from query 2. Your second version runs everything as a single query, so will not have this issue (but others have pointed out other differences between the queries)
Related
There are two tables; X_User_Role and Role like this
X_User_Role table:
************************
UserRoleID UserID RoleID
************************
1 1 1
************************
2 1 2
************************
3 2 1
Role table:
********************************
RoleID Name SecondaryFl
********************************
1 PrimaryRole 0
********************************
2 SecondaryRole 1
********************************
Now I am writing a select statement with joins so that in my final output it should come as (considering only 1 user ID) :
UserID PrimaryRoleName SecondaryRoleName
***********************************************************
1 PrimaryRole SecondaryRole
I have tried joining like this:
select xur.UserID, r1.Name as PrimaryRoleName, r2.Name as SecondaryRoleName
from X_User_Role xur
JOIN Role r1
ON r1.RoleID = xur.RoleID
JOIN Role r2
ON r2.RoleID = r1.RoleID AND SecondaryFl = 1
But I always get output like this:
UserID PrimaryRoleName SecondaryRoleName
***********************************************************
1 PrimaryRole PrimaryRole
I have tried different variations of the above joins but I never get the desired output. I am not able to figure out what I am doing wrong. I am a complete novice at SQL. Can anyone please assist?
Note: I have to use JOINS because this is a part of a bigger select which is entirely made up of JOINS.
Conditional aggregation should be used
select xur.userId,
max(case when SecondaryFl = 0 then r.name end) as PrimaryRoleName,
max(case when SecondaryFl = 1 then r.name end) as SecondaryRoleName
from X_User_Role xur
join Role r on r.RoleID = xur.RoleID
group by xur.userId;
Edit by (YogeshSharma)
Always include where clause while doing the conditional aggregation as because in case SecondaryFl column has more value other than above then it will include null rows always.
select xur.userId,
max(case when SecondaryFl = 0 then r.name end) as PrimaryRoleName,
max(case when SecondaryFl = 1 then r.name end) as SecondaryRoleName
from X_User_Role xur
join Role r on r.RoleID = xur.RoleID
where SecondaryFl in (1, 0) -- Always include especially for conditions aggregation
group by xur.userId;
You can use a pivot query like below
see live demo
On your note:
I have to use JOINS because this is a part of a bigger select which is entirely made up of JOINS.
you can always encapsulate below query as a nested query in a JOIN
select
UserId,
PrimaryRoleName=[0],
SecondaryRoleName=[1]
from
(
select
X.UserID,
Name,
SecondaryFl
from
X_User_Role X
left join Role R
on X.RoleID=R.RoleID
) src
pivot
(
max(Name) for SecondaryFl in ([0],[1])
)p
if you absolutely want a JOIN syntax, you can try below query
select
UserID=X.UserID,
PrimaryRoleName=MAX(case when SecondaryFl=0 then Name else NULL end),
SecondaryRoleName=MAX(case when SecondaryFl=1 then Name else NULL end)
from
X_User_Role X
left join Role R
on X.RoleID=R.RoleID
group by X.UserID
There's a few facts missing from the question I think. Like, what qualified a role to be seconday and primary? But for this answer I will assume that the SecondaryFl field indicates this. 0 for primary and 1 for secondary.
I believe that the problem you are seeing is due to this from you query:
JOIN Role r2
ON r2.RoleID = r1.RoleID AND SecondaryFl = 1
Since you are joining the Role table a second time, on the same primary key. Instead you want to join it again, but with it's own conditions.
Like this:
select
user_role.UserID,
role_primary.Name as PrimaryRoleName,
role_secondary.Name as SecondaryRoleName
from X_User_Role as user_role
join Role as role_primary
on role_primary.RoleID = user_role.RoleID and SecondaryFl = 0
join Role as role_secondary
on role_secondary.RoleID = user_role.RoleID and SecondaryFl = 1
Sorry that I changed your names, I just find it more readable. It should illustrate the point clearer here I think.
EDIT: I assumed that the roles would always be present here. In case that roles are optional, you could use a left join instead, and handle returned nulls with something like coalesce(role_primary.Name, 'None') or just treat the returned null where you are receiving the results.
Like this:
select
user_role.UserID,
coalesce(role_primary.Name, 'None') as PrimaryRoleName,
coalesce(role_secondary.Name, 'None') as SecondaryRoleName
from X_User_Role as user_role
left join Role as role_primary
on role_primary.RoleID = user_role.RoleID and SecondaryFl = 0
left join Role as role_secondary
on role_secondary.RoleID = user_role.RoleID and SecondaryFl = 1
Returning a dynamic number of columns? You are looking for trouble.
What if the user has three, four, five roles?
You should return the roles, one per row. A simple SQL join will do.
This is what I was suggesting in my comment:
select xur.UserID, r1.Name as PrimaryRoleName, r2.Name as SecondaryRoleName
from X_User_Role xur
JOIN Role r1
ON r1.RoleID = xur.RoleID AND r1.SecondaryFl <> 1
JOIN Role r2
ON r2.RoleID = xur.RoleID AND r2.SecondaryFl = 1
WHERE xur.UserID=1
Just wanted to post another answer that doesn't resort to GROUP BY:
select x1.userid, r1.name, r2.name
from x_user_role x1, role r1, x_user_role x2, role r2
where r1.roleid = x1.roleid and r1.secondaryfl = 0
and x1.userid = 1
and r2.roleid = x2.roleid and r2.secondaryfl = 1
and x2.userid = x1.userid
select
*
from
[platformnew].[dbo].[users] u
where u.Phone not in
(select case
when convert(varchar(100),phonenumber) <> '' then convert(varchar(100),ISNULL(PhoneNumber,0))
else convert(varchar(100),0)
end phonenumber
from
[ecommerce_crm].[dbo].[mpcustomer]
)
and u.Phone not in
(select case
when convert(varchar(100),phonenumber2) <> '' then convert(varchar(100),ISNULL(PhoneNumber2,0))
else convert(varchar(100),0)
end phonenumber2
from [ecommerce_crm].[dbo].[mpcustomer]
)
and u.Email not in
(select ISNULL(Email,'')
from [ecommerce_crm].[dbo].[mpcustomer])
and u.Email not in
(select ISNULL(Email2,'')
from [ecommerce_crm].[dbo].[mpcustomer])
this query takes too much time to execute,i think it takes around 3 more minutes,please help me to solve it
you need to change the Not in to not Exists like this for example
select
*
from
[platformnew].[dbo].[users] u
where u.Phone not exists
(select 1 from
[ecommerce_crm].[dbo].[mpcustomer]
WHERE convert(varchar(100),ISNULL([ecommerce_crm].[dbo].[mpcustomer].PhoneNumber,0)) = u.Phone
)
and for the convert part you only need isnull convert(varchar(100),ISNULL([ecommerce_crm].[dbo].[mpcustomer].PhoneNumber,0))
just remove the case when
You should see performance increase when you change all NOT IN clauses to NOT EXISTS. E.g:
and not exists
(
select 1
from [ecommerce_crm].[dbo].[mpcustomer] mpc
where u.Phone = mpc.Phone
)
Also, all CONVERT functions are unnecessary. If phonenumber data type is int, then write your clauses using this type, e.g isnull(phonenumber,0)<>0. And if phone numbers should not be null or 0, add it as separate conditions, because now every time when it's null or 0, you unnecessarily look up other tables to find null and 0 there to discard it.
SELECT *
FROM [platformnew].[dbo].[users] u
WHERE NOT EXISTS (
SELECT 1
FROM [ecommerce_crm].[dbo].[mpcustomer] c
WHERE c.phonenumber = u.Phone
OR c.phonenumber2 = u.Phone
OR c.Email = u.Email
OR c.Email2 = u.Email
)
AND u.Phone != '0'
AND u.Email != ''
I would like to write a procedure to database which will return select all data from database Tournaments plus bool parameter. If user is registered, it will return true.
Call:
exec TournamentsWithLoggedUser #user = 'asd123'
Procedure:
CREATE PROCEDURE [dbo].[TournamentsWithLoggedUser]
#user nvarchar(128)
AS
SELECT
t.Id, t.Info, BIT(r.Id)
FROM
Tournaments AS t
LEFT JOIN
Registrations AS r ON t.Id = r.TournamentId
WHERE
r.UserId IS NULL OR r.UserId = #user
RETURN
it mean something like
1, 'some info', true //1
2, 'some info2', false //2
Why not just use a case statement?
CASE WHEN r.Id IS NULL THEN 0 ELSE 1 END
Change the 0 and 1 to whatever you want for false and true.
SELECT t.Id, t.Info,
-- this works in SQL Server
CAST ((CASE WHEN r.UserId IS NOT NULL THEN 1 ELSE 0 END) AS BIT) AS IsRegistered
FROM Tournaments as t
LEFT JOIN Registrations as r ON t.Id = r.TournamentId
where (r.UserId = '' OR r.UserId = #user)
-- i think this one is help for you...
You are looking for this query
SELECT t.id,
t.info,
Cast (CASE
WHEN r.userid IS NOT NULL THEN 1
ELSE 0
END AS BIT) AS IsRegistered
FROM tournaments AS t
LEFT JOIN registrations AS r
ON t.id = r.tournamentid
AND r.userid = #user
You should clarify what SQL language you are actually using, but an answer can be provided anyway:
CREATE PROCEDURE [dbo].[TournamentsWithLoggedUser]
#user nvarchar(128)
AS
BEGIN
SELECT t.Id, t.Info,
-- this works in SQL Server
CAST ((CASE WHEN r.UserId IS NOT NULL THEN 1 ELSE 0 END) AS BIT) AS IsRegistered
FROM Tournaments as t
LEFT JOIN Registrations as r ON t.Id = r.TournamentId
where r.UserId IS NULL OR r.UserId = #user
-- this should not be required
RETURN
END
However, there is a problem with the logic:
#user is not nullable, so your procedure gives the impression that it looks data for a single user. However, your OR operator allows to select all records from unregistered users united with the record for the particular provided user (if exists).
I'm trying to get sql statement to link from one table to another and use a case (or if) if the user has accesslevel 1 then the statement should be select * from campaigns, whereas if ur not accesslevel 1 u should get the select statement as :
select * from campaigns WHERE campaign_Creator = ${user_ID}
SELECT * FROM campaigns
INNER JOIN users ON campaigns.CAMPAIGN_CREATOR = users.USER_ID
CASE WHEN users.USER_ACCESSLEVEL = 1
THEN SELECT * FROM campaigns
ELSE select * from campaigns WHERE CAMPAIGN_CREATOR = ${user_ID};
How would I go around creating such a statement? I've been trying to look it up but i just get more confused as to how to go around with this.
Perhaps this is what you want?
SELECT * FROM campaigns
INNER JOIN users ON campaigns.CAMPAIGN_CREATOR = users.USER_ID
WHERE users.USER_ACCESSLEVEL = 1
OR CAMPAIGN_CREATOR = ${user_ID};
I agree with the solution of our friend and complementing follow my suggestion.
SELECT *
FROM campaigns
INNER JOIN users ON campaigns.CAMPAIGN_CREATOR = users.USER_ID
AND (users.USER_ACCESSLEVEL = 1 OR (users.USER_ACCESSLEVEL != 1
AND CAMPAIGN_CREATOR = ${user_ID}))
I have two tables, Users and #TempTable (which is a subset of Users). I would like to update a column, IsActive, in the Users table. I would like to set IsActive = 1 if a user that is in #TempTable is also in the Users table, and set IsActive = 0 otherwise.
Getting the users from Users that are NOT in #TempTable (IsActive should be set to 0 for these users):
-- (Users \ #TempTable) U (#TempTable \ Users)
SELECT u.UserName
FROM Users u
WHERE (u.UserName) NOT IN
(SELECT t.[User Name] FROM #TempTable t)
UNION ALL
SELECT t.[User Name]
FROM #TempTable t
WHERE (t.[User Name]) NOT IN
(SELECT u.UserName FROM Users u)
Let's call this the ResultSet. I would appreciate some help with my UPDATE statement. What I'd like to be able to do is:
UPDATE Users
SET IsActive = (CASE WHEN User.UserName IN ResultSet THEN 0 ELSE 1 END)
without having to write out the CASE WHEN for each User.UserName. Thanks in advance!
You can use a join in the UPDATE statement.
UPDATE Users
SET Users.Active = CASE WHEN T.UserName is null THEN 0 ELSE 1 END
FROM Users AS U
LEFT JOIN #TempTable AS T ON U.UserName = T.UserName
Notes :
You could also use a sub-query but that would be much slower (order of n squared not order of n). For a small number of users this would not matter.
I did not test so I could have a typo / bug in the code above.
Based on crazy comments about how this would not work I implemented a fiddle.
Enjoy it working:
http://sqlfiddle.com/#!6/25235/3