October 15, 2003 at 12:50 pm
In a stored procedure report, how do I allow an optional filter for a select statement/
For example:
use pubs
go
CREATE PROCEDURE au_info @lastname varchar(40), @firstname varchar(20) AS
SELECT au_lname, au_fname
FROM authors
WHERE au_lname = @lastname and au_fname = @firstname
go
EXECUTE au_info @firstname = null, @lastname = 'Ringer'
GO
DROP PROCEDURE au_info
I want the stored procedure to return all records where last name is "ringer" (there should be two of them) but right now it returns nothing.
Thanks in advance,
Billy
October 15, 2003 at 1:17 pm
ALTER PROCEDURE au_info @lastname varchar(40), @firstname varchar(20) AS
SELECT au_lname, au_fname
FROM authors
WHERE au_lname = @lastname OR au_fname = @firstname
GO
EXECUTE au_info @firstname = NULL, @lastname = 'Ringer'
GO
October 15, 2003 at 1:22 pm
bp,
Your query is only going to find those records like this:
au_fname au_lname
NULL ringer
That's the word NULL.
srgangu's script will find any records where
au_fname is NULL or au_lname is ringer.
I believe you want all records where the au_lname is ringer and the au_fname is null (in other words blank).
If so change
au_fname = @firstname
to read
aufname IS NULL
-SQLBill
October 15, 2003 at 1:27 pm
To add to my last post...
both of you are searching for the WORD NULL. @lastname is a VARCHAR. NULL (meaning empty) is not VARCHAR.
Using = means to match (equality). You can't make a match to NULL (empty value). SQL Server has the IS NULL statement to search for the NULL (empty value).
-SQLBill
October 15, 2003 at 2:54 pm
Actually, I only want to select records where last name is "Ringer". It does not matter what the first name is. I can't leave out first name parameter because otherwise the sproc will complain it is missing. Not sure how I can accomplish that (that is, I want the filters to be optional; I want the sproc to be able to filter without first and last name, either or both.)
Thanks in advance,
Billy
October 15, 2003 at 5:40 pm
Try this,
use pubs
go
CREATE PROCEDURE au_info
@lastname varchar(40) = NULL
, @firstname varchar(20) = NULL
AS
SELECT au_lname, au_fname
FROM authors
WHERE (au_lname = @lastname or au_fname = @firstname)
go
EXECUTE au_info @lastname = 'Ringer'
GO
DROP PROCEDURE au_info
The two changes of note are,
1) use = NULL on the parameter definition in the CREATE PROCEDURE statement
2) use OR instead of AND in the WHERE clause
Also, the following uses wildcard matching and will return 3 records, matching with 'Stringer' and 'Ringer'
use pubs
go
CREATE PROCEDURE au_info
@lastname varchar(40) = NULL
, @firstname varchar(20) = NULL
AS
SET @lastname = '%' + @lastname + '%'
SET @firstname = '%' + @firstname + '%'
SELECT au_lname, au_fname
FROM authors
WHERE (au_lname LIKE @lastname or au_fname LIKE @firstname)
go
EXECUTE au_info @lastname = 'Ringer'
GO
DROP PROCEDURE au_info
Hope this helps
Phill Carter
--------------------
Colt 45 - the original point and click interface
--------------------
Colt 45 - the original point and click interface
October 15, 2003 at 6:06 pm
Thanks... just wondering you would consider piecing together the sql statement and running it. I tried it and it appears to execute a lot faster. Below is the code to display this.
use pubs
go
CREATE PROCEDURE au_info1 @lastname varchar(40) = NULL, @firstname varchar(20) = NULL AS SELECT au_lname, au_fname FROM authors WHERE (au_lname = @lastname or au_fname = @firstname)
go
CREATE PROCEDURE au_info2 @lastname varchar(40) = NULL, @firstname varchar(20) = NULL AS SET @lastname = '%' + @lastname + '%'SET @firstname = '%' + @firstname + '%' SELECT au_lname, au_fname FROM authors
WHERE (au_lname LIKE @lastname or au_fname LIKE @firstname)
GO
CREATE PROCEDURE au_info3 @lastname varchar(40) = NULL, @firstname varchar(20) = NULL AS
SELECT au_lname, au_fname
FROM authors
WHERE au_lname = @lastname
union
SELECT au_lname, au_fname
FROM authors
WHERE au_fname =@firstname
go
CREATE PROCEDURE au_info4 @lastname varchar(40) = NULL, @firstname varchar(20) = NULL AS
declare @STMT varchar(8000)
SET @STMT = 'SELECT au_lname, au_fname FROM authors WHERE 1=1 '
IF (@lastname IS NOT NULL)
SET @STMT = @STMT + ' AND au_lname = ''' + @lastname + ''''
IF (@firstname IS NOT NULL)
SET @STMT = @STMT + ' AND au_fname = ''' + @firstname + ''''
EXEC (@stmt)
go
GO
print convert(varchar(50), getdate(), 113)
EXECUTE au_info1 @lastname = 'Ringer'
print convert(varchar(50), getdate(), 113)
EXECUTE au_info2 @lastname = 'Ringer'
print convert(varchar(50), getdate(), 113)
EXECUTE au_info3 @lastname = 'Ringer'
print convert(varchar(50), getdate(), 113)
EXECUTE au_info4 @lastname = 'Ringer'
print convert(varchar(50), getdate(), 113)
GO
DROP PROCEDURE au_info1
DROP PROCEDURE au_info2
DROP PROCEDURE au_info3
DROP PROCEDURE au_info4
October 16, 2003 at 2:51 am
hello,
you might even try this 'easy' way in the where-statement:
where
(@firstname is null or au_fname like @firstname+'%')
and
(@lastname is null or au_lname like @lastname+'%')
October 16, 2003 at 5:13 am
What you seem to really want is to match anything where the field supplied is null, and match the supplied string if not null:
CREATE PROCEDURE au_info
(
@lastname varchar(40) = null,
@firstname varchar(40) = null
)
AS
SELECT au_lname, au_fname
FROM authors
WHERE au_lname like IsNull(@lastname,'%')
and au_fname like IsNull(@firstname,'%')
go
This will work when a parameter is left out, supplied as null, and when the caller uses '%' in the values.
Unless the null is inside quotes, you are matching on a null value, not the word null as some posters suggested. In your original query, the column au_fname would have to have been null to match.
Sloan
Sloan
If you can't do it in SQL, get a bigger hammer!
October 16, 2003 at 6:49 am
It certainly took awhile for someone to point out the use of IsNull(). Sloan definitely hit the target.
October 16, 2003 at 7:43 am
You can also use a different query in each case. I resort to this when I can't get one query to execute quickly for all cases. This query is sort enough that it's easy.
IF @ExactMatch = 0 BEGIN -- partial match is okay
SET @lastname = @lastname + '%'
SET @firstname= @firstname+ '%'
END
IF @lastname IS NULL AND @firstname IS NULL
SELECT au_lname, au_fname
FROM authors
ELSE IF @firstname IS NULL
SELECT au_lname, au_fname
FROM authors
WHERE au_lname LIKE @lastname
ELSE IF @lastname IS NULL
SELECT au_lname, au_fname
FROM authors
WHERE au_fname LIKE @firstname
ELSE
SELECT au_lname, au_fname
FROM authors
WHERE au_lname LIKE @lastname and au_fname LIKE @firstname
RandyHelpdesk: Perhaps Im not the only one that does not know what you are doing. 😉
October 16, 2003 at 11:25 am
Ok... thanks for everyone's responses. However, for discussion purposes, I don't think using the LIKE operator for the optional parameters is not entirely sufficient. What would you do if you want to filter based on datetime? for example (I would like to retrieve all sales records starting from 1/1/1994. then in a second report, I would want all sales records ending 12/31/1993. then in a third report, I would want all sales records in first quarter of 1994.):
use pubs
go
CREATE PROCEDURE sales_info @ord_num varchar(20) = null, @start_date datetime = null, @end_date datetime = null, @payterms varchar(12) = null AS
SELECT * FROM sales WHERE ord_num like IsNull(@ord_num,'%') and payterms like IsNull(@payterms,'%') and ord_date >= @start_date and ord_date < dateadd(d, 1, @end_date)
go
EXECUTE sales_info @ord_num = null, @start_date = '1/1/1994', @end_date = null, @payterms = null
GO
DROP PROCEDURE sales_info
October 16, 2003 at 12:18 pm
This may work for what you want. As long as an unknown value is passed as null it will return the correct results.
For example if the value for @FirstNM is null no records will be filtered out because FirstNM will always be equal to itself and if you pass 'Ringer' for @LastNM it will filter for any records with that value. I also included a date range filter but you will need to adjust the datepart to suit your needs.
CREATE Procedure usp_TestVariables (
--general search fields
@FirstNM varchar(25) = null,
@LastNM varchar(25) = null,
@MinValue int = null,
@MaxValue int = null,
@StartDate datetime = null,
@EndDate datetime = null)
AS
Select *
from table1
-- Check to for a value is within a range, set defaults to lowest and highest possible values
Where value BETWEEN ISNULL(@MinValue,0) AND ISNULL(@MaxValue,999999999)
-- Check for an exact match on first name
and FirstNM = ISNULL(@FirstNM,FirstNM)
-- Check for a like match on last name
and LastNM Like ISNULL('%'+@LastNM+'%',LastNM)
-- Check for a date range
and datediff(d, DateValue,Getdate())
between datediff(d,@StartDate, Getdate())
and datediff(d,@EndDate, Getdate())
October 17, 2003 at 12:46 am
Hi,
change your proc as shown below
CREATE PROCEDURE au_info @lastname varchar(40), @firstname varchar(20) AS
SELECT au_lname, au_fname
FROM authors
WHERE au_lname = isnull(@lastname,au_lname) and au_fname = isnull(@firstname,au_fname)
go
EXECUTE au_info @firstname = null, @lastname = null
GO
DROP PROCEDURE au_info
October 17, 2003 at 7:08 am
One other way to write this sort of query - which I find to be a very useful technique is :-
CREATE PROCEDURE au_info @lastname varchar(40), @firstname varchar(20) AS
SELECT au_lname, au_fname
FROM authors
WHERE au_lname = @lastname
and au_fname = case isnull(@firstname,'')='' then au_fname else @firstname end
GO
EXECUTE au_info @firstname = '', @lastname = 'Ringer'
GO
This way it doesn't matter if there is a value in au_fname or not.!
Viewing 15 posts - 1 through 15 (of 24 total)
You must be logged in to reply to this topic. Login to reply