I'm creating a stored procedure that should return a list of users based on a boolean flag #status as follows:
If status is not informed, the query must return all users
If 'status' is passed as true, the query must return only users where the column LastAccess is not null.
If status is passed as false, the query must return users which column LastAccess is null.
This column is of type datetime.
I'm ok dealing the first use case, with #status is null in the last line of the following code:
CREATE PROCEDURE selectUsersByStatus (
#userId int,
#status bit
)
AS
SELECT * from users
WHERE users.id = #userId
and (#status is null or CASE #status WHEN 1 THEN (users.LastAccess is not null) ELSE (users.LastAccess is null))
However the rest of the line obviously doesn't work. How to proceed?
Thanks
Try simple:
CREATE PROCEDURE selectUsersByStatus (
#userId int,
#status bit
)
AS
SELECT * from users
WHERE users.id = #userId
and (#status is null OR (#status = 1 AND users.LastAccess IS NOT NULL) OR (#status = 0 AND users.LastAccess IS NULL))
Related
I have the following query (SQL server):
DECLARE #UserId INT;
SET #UserId = //... set by dynamic variable
SELECT *
FROM Users
WHERE userId = #UserId
My issue is that if the #UserId is null the query will not evaluate correctly.
How can I write this query to evaluate correctly if the variable is null or not null?
EDIT:
There have been many suggestions to use the following:
WHERE (#UserId IS NULL OR userId = #UserId)
OR similar.
In this case, if there is a table of 3 entries, with userId of 1,2 and 3 the variable '#UserId' IS NULL, this query will return all 3 entries. What I actually need it to return is no entries, as none of them have a userId of NULL
You need to use an OR:
DECLARE #UserId INT;
SET #UserId = //... set by dynamic variable
SELECT *
FROM Users
WHERE (userId = #UserId OR #UserId IS NULL);
This, however, could well have (severe) performance issues if you're writing this in a Stored Procedure, reusing this code a lot or adding more NULLable parameters. If so, include OPTION (RECOMPILE) in your query so that the query plan is generated each time it's run. This will stop the Data Engine using query plans generated that had a different set of NULL parameters.
Edit: The OP wasn't clear on their question. They don't want to pass the value NULL for #UserID and return all rows, they want to pass NULL and get rows where UserID has a value of NULL. That would be:
SELECT *
FROM Users
WHERE UserID = #UserID
OR (UserID IS NULL AND #UserID IS NULL);
After reading the edit, i think you want your query like
SELECT *
FROM Users
WHERE COALESCE(userId ,0) = COALESCE(#UserId,0)
Edit:
As pointed by Gordon Linoff & Larnu that above query will not be good in terms of performance as the query is "non-SARGable", for the better performance same query can be written as
SELECT *
FROM Users
WHERE userId = #UserId OR( userId is null and #UserId is null)
use coalesce
SELECT *
FROM Users
WHERE userId = coalesce(#UserId,val)
You can simplify the Boolean logic instead :
WHERE (#UserId IS NULL OR userId = #UserId)
Try this
DECLARE #UserId INT;
SET #UserId = //... set by dynamic variable
SELECT *
FROM Users
WHERE userId= (case when #UserId is null then userId else #UserId end)
I haven't seen the use of INTERSECT suggested so far so putting this out there as an alternative that also results in easy to read SQL when your list of potentially NULL variables might be long.
SELECT *
FROM Users
WHERE EXISTS (
SELECT UserId
INTERSECT SELECT #UserId
)
This pattern is useful when you have other variables to check e.g.
SELECT *
FROM Users
WHERE EXISTS (
SELECT
UserId,
Username,
UserRole
INTERSECT SELECT
#UserId,
#Username,
#UserRole
)
I have to write a query for a login page where the user can enter either emailid(varchar datatype) or userid(int datatype). How do I write a query for this without knowing the datatype of the input?
CREATE PROCEDURE my_stored_procedure
#emailId nvarchar(50) = NULL,
#userId int = NULL
AS
SET NOCOUNT ON;
IF (#emailId IS NOT NULL) AND (LEN(#emailId) > 0)
SELECT * FROM MYTABLE WHERE EmailId = #emailId
ELSE
SELECT * FROM MYTABLE WHERE UserId = #UserId
GO
Your input parameter should be of varchar type.
Then in your procedure use ISNUMERIC function to check for number. Have two queries based on that with IF statement in case if it is int or varchar.
DECLARE #userInput VARCHAR(50)
IF ISNUMERIC(#userInput) = 1
BEGIN
-- Your query with userid
END
ELSE
BEGIN
-- Your query with emailid
END
Try this query it may help you.
DECLARE #emailid varchar(250),#userid bigint
set #emailid='A'
SET #userid=3
select * from yourtable
where case when #emailid='A' THEN 'A' ELSE emailid END=#emailid
AND case when #userid=0 THEN 0 ELSE userid END=#userid
Note: You should pass 'A' as default value for email_id and 0 for userid or else you can pass your required input
I created a stored procedure which when passed nothing as parameter should return the entire table. But if the studentId is passed, then return her details.
Something like this
create procedure usp_GetStudents #studentId int = null
as
if (#studentId = null)
select * from Student
else
select * from Student where studentId = #studentId
Output
exec usp_GetStudents -- No records returned though there are records in the table
exec usp_GetStudents #studentId = null -- No records returned
exec usp_GetStudents #studentId = 256 -- 1 entry returned
Just curious to know if anything is wrong in the syntax/logic for returning all the entries of the table?
Thank you
You're trying to test for null using =, a comparison operator. If you're using ANSI nulls, any comparison against null is false.
Where #studentId is any value (or null) the following expressions are all false:
#studentId = null -- false
#studentId > null -- false
#studentId >= null -- false
#studentId < null -- false
#studentId <= null -- false
#studentId <> null -- false
So, in order to test for null you must use a special predicate, is null, i.e.:
#studentId is null
Shorter way to do that:
create procedure usp_GetStudents #studentId int = null
as
select * from Student
where studentId = isnull(#studentId,studentId)
You can't chack if value is null using =.
For your example you have to replace condition #studentId = null to is null syntax.
Try to change your code as below:
create procedure usp_GetStudents #studentId int = null
as
if (#studentId is null)
select * from Student
else
select * from Student where studentId = #studentId
Change the = to an is
create procedure usp_GetStudents #studentId int = null
as
if (#studentId is null)
select * from Student
else
select * from Student where studentId = #studentId
I am passing two parameters i.e #AccountId and #key. I want to show all the values present in the database for #AccountId and #key when there is no values in the parameters i.e #AccountId and #key. I want to do this for the same dataset. Is this possible or i have create different datasets?
The query which I am using is :
CREATE PROCEDURE [dbo].[GetDenyList]
#AccountId nvarchar(100),
#key nvarchar(400)
AS
select New_AccountId AS 'AccountId/Key', New_Description AS 'Reason',CreatedOn AS 'Date'
from abc.dbo.New_keydenylist
where New_AccountId is not null
AND #AccountId = New_AccountId
union all
select new_key AS 'AccountId/Key', New_Description AS 'Reason',CreatedOn AS 'Date'
from abc.dbo.New_keydenylist
where New_key is not null
and #Key=New_key
If I understand your question well, you have to use any predicate that always evaluate to true regardless to the parameters' values passed to the WHERE clause. For example WHERE 1 = 1:
WHERE 1 = 1
AND (#AccountId IS NOT NULL OR AccountId = #AccountId)
The same with #key parameter:
WHERE 1 = 1
AND (#key IS NOT NULL OR New_key = #key)
If the two parameters #key and #AccountId are both NULL or one of them, then the WHERE clause still be valid and return all the row as it were not presented.
Check for null or equivalence on the parameter:
AND ((#AccountId IS NULL) OR (#AccountId = New_AccountId))
I want to get a parameter from a select clause in one time, instead of two selects.
Currently, I'm doing this :
SELECT
Idx_Pro,
Name,
Mail,
IsValidateUser
FROM
MyTable
WHERE
[Mail] = #Mail
AND
[Password] = #password
If (##ROWCOUNT > 0)
SET #Id_output = (SELECT Id_User
FROM MyTable
WHERE [Mail] = #Mail
AND [Password] = #password
)
I tried this :
DECLARE #Id_output int
SELECT
[#Id_output] = Idx_Pro,
...
FROM MyTable
...
But I can't get it ...
Is it even possible to get only one column in a variable ? (My select returns only one row)
thanks,
TonyFlow
Are you looking to both return the 4 column result and assign to the variable in one operation? If so that isn't possible. You could assign all the column values to variables or parameters then select those to return the result set though.
DECLARE #Idx_Pro INT,
#Name VARCHAR(50),
#IsValidateUser BIT
SELECT #Idx_Pro = Idx_Pro,
#Name = Name,
#IsValidateUser = IsValidateUser
FROM MyTable
WHERE [Mail] = #Mail
AND [Password] = #password
/*No intermediate statement can be placed here as it will reset ##ROWCOUNT*/
SELECT #Idx_Pro AS Idx_Pro,
#Name AS Name,
#Mail AS Mail,
#IsValidateUser AS IsValidateUser
WHERE ##ROWCOUNT > 0