SQL update rows in column using CASE statement - sql

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

Related

How to set a value in 1 table according to the count of a value in another table

The database I am using (It is in a relationship with table 1):
Sample Data for Table1
I want to set Present Count in Accounts according to the number of 'P' characters in Table1.Attendance (Right now, it is manually set). I tried making a 'Counting' query that looks like this
UPDATE Accounts SET [Present Count] = (SELECT Count(*) FROM Table1 WHERE Table1.Attendance = 'P')
WHERE Accounts.Username = Table1.Username
I tried this too
SELECT Count(Table1.Attendance) AS PCount HAVING ((Count(Table1.Attendance))='P'), Count(Table1.Attendance) AS ACount HAVING (Count(Table1.Attendance))='A'
FROM Table1
GROUP BY Username
But this won't work, giving no error, no update or anything
This as well:
UPDATE Accounts
SET [Present Count] = (SELECT Count(*)
FROM Table1
WHERE Table1.Attendance = 'P' AND
Accounts.Username = Table1.Username
);
This displays the count i have set in the table manually, not the count calculated from the total number of 'P's
You could try using a inner join on the subquery for count group by username
UPDATE A
SET A.[Present Count] = t.my_count
FROM Accounts AS A
INNER JOIN (
SELECT username, Count(*) AS my_count
FROM Table1
WHERE Table1.Attendance = 'P'
GROUP BY username
) AS t ON A.Username = t.Username
The correct syntax is:
UPDATE Accounts
SET [Present Count] = (SELECT Count(*)
FROM Table1
WHERE Table1.Attendance = 'P' AND
Accounts.Username = Table1.Username
);
EDIT:
What values does this return?
SELECT UserName, Count(*)
FROM Table1
WHERE Table1.Attendance = 'P'
GROUP BY Username
Perhaps what you see as 'P' isn't really 'P' and you are just getting 0 for everything because nothing matches.

Select Statement with INNER JOIN AND CASE

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}))

improving sql query in the case of many ORs

I have an SQL query which can have around 1.5k of IDs OR'ed in the following form. They are the IDs of people I have and they are individually selectable, hence the many ORs when everyone is selected. Is it better to just SELECT everyone's ID then put it in the AND condition, UNION instead of OR, or perhaps use IN to bunch up all IDs, since the user may select everyone accept 1 person. Thanks.
...
AND (
(UserID = '53b95690-22d8-44a2-ad56-919cb4037218')
OR (UserID = '87b7fc0c-28f4-4f2e-9909-066df42245fa')
OR (UserID = '98c1b5e3-6ba5-4bd9-b8f5-d3b2221e3e3a')
OR...
EDIT: The complete query, as requested;
SELECT *
FROM Mail WITH (NOLOCK)
WHERE Active= 1
AND Company= '1d034e8b-0122-4531-8795-895d9287920f'
AND (
CompanyDivisionID= '129bcca1-b1d8-4a9e-8152-0b9e936c9d01'
OR CompanyDivisionID= '1bf4023d-22a3-4520-b751-7842576f42b7'
)
AND (
(DestinationUserID = '53b95690-22d8-44a2-ad56-919cb4037218')
OR (DestinationUserID = '87b7fc0c-28f4-4f2e-9909-066df42245fa')
OR (DestinationUserID = '98c1b5e3-6ba5-4bd9-b8f5-d3b2221e3e3a')
...
...
...
OR (DestinationUserID = '8c78fc05-7969-48fd-9b30-774e5d9a70bd')
OR (DestinationUserID = 'e7b76096-fe7d-44b8-9158-8293ac609471')
OR (DestinationUserID = '8a6b7385-4339-43fb-b95b-a7b687982bcd')
)
ORDER BY SendingDate DESC
Create a (temporary) table containing your selected UserIDs and join to that table.
SELECT *
FROM Mail WITH (NOLOCK)
inner join SelectedUsers on mail.DestinationUserID = SelectedUsers.UserID
WHERE Active= 1

How to update column value based on records existing in two different tables?

Is there a better way of doing the following? (Instead of having two separate queries) I want to update the UserTypeId column to either 'USER1'
or 'USER2' if a record exists in the AdminDetails table.
UPDATE Usernames
SET UserTypeId = (select Id from UserTypes where code = 'USER1')
WHERE EXISTS
(SELECT AdminDetails.Id
FROM AdminDetails
WHERE AdminDetails.Id = Usernames.Id)
UPDATE Usernames
SET UserTypeId = (select Id from UserTypes where code = 'USER2')
WHERE EXISTS
(SELECT AdminDetails.Id
FROM AdminDetails
WHERE AdminDetails.Id = Usernames.Id)
I tried using COUNT() but I got the following error when attempting to do this in one query using an inner join and case statement:
UPDATE Usernames
SET UserTypeId = (CASE WHEN COUNT(AdminDetails.Id) > 0 THEN 'USER1' ELSE 'USER2' END)
FROM AdminDetails
INNER JOIN Usernames AS un
ON AdminDetails.Id = un.UserId
But it gives the following error: 'An aggregate may not appear in the set list of an UPDATE statement'.
I want to do this in one query using case when then else by checking if a record exists. How can I do this?
You can try something like this, using EXISTS within the CASE statement:
UPDATE Usernames
SET UserTypeId = (CASE WHEN EXISTS
(SELECT AdminDetails.Id
FROM AdminDetails
WHERE AdminDetails.Id = Usernames.Id)
THEN 'USER1' ELSE 'USER2' END)
NOTE: This would update all records where the IDs are in both tables unless you add a WHERE clause on to it. Also, I'm not sure that you would want to update the UserTypeId with the values USER1 and USER2, which is what your third UPDATE statement is trying to do. Without seeing your full database schema it's hard to be exact.

Are both queries the same?

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)