October 6, 2016 at 4:22 am
I have this problem I cannot solve. In a stored procedure I need to make a select query. A parameter passed to the SP tells to select only the record with that ID. If the parameter is zero then all records are selected.
I tried several things with IF and CASE WHEN, but neither work. Can this be solved?
create procedure stp_test (@only_this_record int)
as
begin
select * from test where (field1=1) and ...etc...
if @only_this_record > 0
and (id=@only_this_record)
end
October 6, 2016 at 4:33 am
marc.corbeel (10/6/2016)
I have this problem I cannot solve. In a stored procedure I need to make a select query. A parameter passed to the SP tells to select only the record with that ID. If the parameter is zero then all records are selected.I tried several things with IF and CASE WHEN, but neither work. Can this be solved?
create procedure stp_test (@only_this_record int)
as
begin
select * from test where (field1=1) and ...etc...
if @only_this_record > 0
and (id=@only_this_record)
end
Using a conditional IF statement is by far the simplest way of doing this.
😎
USE TEEST;
GO
SET NOCOUNT ON;
DECLARE @NUM INT = 0;
IF (@NUM > 0)
BEGIN
SELECT
NM.N
FROM dbo.TBL_NUMBERS NM
WHERE NM.N = @NUM;
END
ELSE
BEGIN
SELECT
NM.N
FROM dbo.TBL_NUMBERS NM;
END
October 6, 2016 at 4:41 am
Yes but here you include the complete select command in the condition.
Problem is here that my real query is very complex (about 40 lines), and putting it 2 times in the procedure makes maintenance much harder.
Isn't there a way to only put a part of the query in the condition?
October 6, 2016 at 4:47 am
marc.corbeel (10/6/2016)
Yes but here you include the complete select command in the condition.Problem is here that my real query is very complex (about 40 lines), and putting it 2 times in the procedure makes maintenance much harder.
Isn't there a way to only put a part of the query in the condition?
Yes, there is. But think about this for a moment. An execution plan set will be created and saved for the stored procedure. But which execution plan - the one for a single row, or the one for all of them? What do you think will happen if the saved plan favours a single row and you then execute the procedure with the 'all rows' option? There's another answer to this of course, but it comes at a cost...
For fast, accurate and documented assistance in answering your questions, please read this article.
Understanding and using APPLY, (I) and (II) Paul White
Hidden RBAR: Triangular Joins / The "Numbers" or "Tally" Table: What it is and how it replaces a loop Jeff Moden
October 6, 2016 at 5:24 am
marc.corbeel (10/6/2016)
Yes but here you include the complete select command in the condition.Problem is here that my real query is very complex (about 40 lines), and putting it 2 times in the procedure makes maintenance much harder.
Isn't there a way to only put a part of the query in the condition?
So what is wrong with creating a view for the main part of the query?
You can then:
SELECT * FROM YourView
SELECT * FROM YourView WHERE ...
etc
October 6, 2016 at 6:09 am
Eirikur Eiriksson (10/6/2016)
Using a conditional IF statement is by far the simplest way of doing this.
And is prone to the performance-related problems that Chris alluded to.
https://www.simple-talk.com/content/article.aspx?article=2280
Gail Shaw
Microsoft Certified Master: SQL Server, MVP, M.Sc (Comp Sci)
SQL In The Wild: Discussions on DB performance with occasional diversions into recoverability
October 6, 2016 at 6:15 am
The select query I talked about is actually part of an INSERT INTO.... SELECT query.
Does this make a difference?
October 6, 2016 at 6:26 am
Using a view is indeed my solution for now. Thanks to all repliers!
October 6, 2016 at 7:57 am
GilaMonster (10/6/2016)
Eirikur Eiriksson (10/6/2016)
Using a conditional IF statement is by far the simplest way of doing this.And is prone to the performance-related problems that Chris alluded to.
https://www.simple-talk.com/content/article.aspx?article=2280
We must be talking cross-purposes here Gail - I was referring to a one-size-fits-all plan, whereas Eirikur's suggestion would exhibit separate plans for the two queries. A little test harness bears this out:
CREATE procedure test01 (@NUM INT) AS
SET NOCOUNT ON;
IF (@NUM > 0) BEGIN
SELECT NM.Number
FROM master.dbo.spt_values NM
WHERE NM.Number = @NUM;
END
ELSE BEGIN
SELECT NM.Number
FROM master.dbo.spt_values NM
END
RETURN 0
GO
EXEC dbo.test01 0 -- Runs an index scan plan
EXEC dbo.test01 120 -- Runs an index seek plan retrieved from cache
EXEC dbo.test01 0 -- Runs an index scan plan retrieved from cache
Whereas this:
ALTER procedure test02 (@NUM INT)
as
SET NOCOUNT ON;
SELECT NM.Number
FROM master.dbo.spt_values NM
WHERE @NUM = 0 OR NM.Number = @NUM;
RETURN 0
EXEC dbo.test02 120
Performs an index scan for a single row, reading 2500 rows in the process.
For fast, accurate and documented assistance in answering your questions, please read this article.
Understanding and using APPLY, (I) and (II) Paul White
Hidden RBAR: Triangular Joins / The "Numbers" or "Tally" Table: What it is and how it replaces a loop Jeff Moden
October 6, 2016 at 11:22 am
ChrisM@Work (10/6/2016)
GilaMonster (10/6/2016)
Eirikur Eiriksson (10/6/2016)
Using a conditional IF statement is by far the simplest way of doing this.And is prone to the performance-related problems that Chris alluded to.
https://www.simple-talk.com/content/article.aspx?article=2280
We must be talking cross-purposes here Gail - I was referring to a one-size-fits-all plan, whereas Eirikur's suggestion would exhibit separate plans for the two queries.
And they both have performance problems, as the article I linked shows. Different problems, but similar cause, that of compiling the query for a different row count that it runs with.
Gail Shaw
Microsoft Certified Master: SQL Server, MVP, M.Sc (Comp Sci)
SQL In The Wild: Discussions on DB performance with occasional diversions into recoverability
October 6, 2016 at 12:49 pm
GilaMonster (10/6/2016)
ChrisM@Work (10/6/2016)
GilaMonster (10/6/2016)
Eirikur Eiriksson (10/6/2016)
Using a conditional IF statement is by far the simplest way of doing this.And is prone to the performance-related problems that Chris alluded to.
https://www.simple-talk.com/content/article.aspx?article=2280
We must be talking cross-purposes here Gail - I was referring to a one-size-fits-all plan, whereas Eirikur's suggestion would exhibit separate plans for the two queries.
And they both have performance problems, as the article I linked shows. Different problems, but similar cause, that of compiling the query for a different row count that it runs with.
For this simple use case, the two different plans, for the two queries, work perfectly well. Pass 0 and you get a scan, pass > 0 and you get a seek. Sure you could mess it all up by adding something rowcount-sensitive to the query, but the simple SELECT works. That's my point.
For better assistance in answering your questions, please read this[/url].
Hidden RBAR: Triangular Joins[/url] / The "Numbers" or "Tally" Table: What it is and how it replaces a loop[/url] Jeff Moden[/url]
October 6, 2016 at 3:37 pm
ChrisM@home (10/6/2016)
Sure you could mess it all up by adding something rowcount-sensitive to the query
Like a key lookup due to a noncovering index on that single table. Yes, the trivial plan case works, but that query form is prone to erratic performance and the optional parameter, depending on the form, is prone to either consistently bad or erratic performance. Imho both should be avoided.
Gail Shaw
Microsoft Certified Master: SQL Server, MVP, M.Sc (Comp Sci)
SQL In The Wild: Discussions on DB performance with occasional diversions into recoverability
October 7, 2016 at 3:02 am
This becomes a little more interesting if you increase the complexity of the query:
CREATE PROCEDURE [dbo].[test04]
(@NUM INT)
AS
SET NOCOUNT ON;
IF (@NUM > 0)
BEGIN
SELECT p.n --
FROM dbo.Numbers NM
INNER JOIN dbo.Numbers p ON p.n = nm.n
WHERE NM.n = @NUM;
END
ELSE
BEGIN
SELECT p.n
FROM dbo.Numbers NM
INNER JOIN dbo.Numbers p ON p.n = nm.n
END
RETURN 0
The estimated plan looks like this, whatever value you use for the parameter:
And of course, it will work correctly every time, because the scan plan doesn't reference a parameter at all, and if the parameter is used, it always selects a single row using the seek plan.
For fast, accurate and documented assistance in answering your questions, please read this article.
Understanding and using APPLY, (I) and (II) Paul White
Hidden RBAR: Triangular Joins / The "Numbers" or "Tally" Table: What it is and how it replaces a loop Jeff Moden
October 7, 2016 at 11:07 am
marc.corbeel (10/6/2016)
Yes but here you include the complete select command in the condition.Problem is here that my real query is very complex (about 40 lines), and putting it 2 times in the procedure makes maintenance much harder.
Isn't there a way to only put a part of the query in the condition?
If the query is complex and you dont want to maintain it in two code blocks, you could opt for a catch all query.
create procedure stp_test
(
@only_this_record int
)
as
set nocount on;
select@only_this_record=nullif(@only_this_record,0);
selectn
fromdbo.tbl_numbers
where(n = @only_this_record or @only_this_record IS NULL);
option(recompile)
;
----------------------------------------------------
October 10, 2016 at 7:47 pm
All of the Basic terms wrong in your post. Rows are not records; columns are not fields. Instead of using a zero, which is an actual numeric value, you probably want to use a null. This is why we put them in SQL; they are placeholders for unknown values.
Here is a common idiom for using the null, as a generic value:
WHERE foobar_id = COALASE(@in_foobar_id, foobar_id)
You might run into some problems with performance, so check it out.
The reason I ask if you meant make or execute is that they are different. New SQL programmers like to use dynamic SQL. Experienced SQL programmers think that dynamic SQL is like fried babies at a barbecue.:w00t:
There is no way to optimize it, collect statistics on it. Over time, or anything else. But, boy howdy!, Dynamic SQL looks like how a lot of people grew up writing BASIC in the 1970 – 1980 timeframe.
In a well-designed SQL database, we have a little different model of the world. The schema represents a known environment, a system in which data flows in and out. We do not have a lot of surprises; we have a running enterprise, with well-defined rules and constraints. Many of these are actually governed by law!
But perhaps more than that you need to get a book on basic software engineering and look at the concepts of coupling and cohesion. When we write code, in any language, we want each module to do one and only one function with a known set of parameters (think mathematical functions); this is called high cohesion. We then want to be able to use these modules of code anywhere we want, like Lego blocks.
The worst sort of modules are those depend on their environment. This thing might be shoe sizes or gross domestic products of South American countries, depending on what flag parameter was passed to it. They are dependent on their environment. WOW!
Books in Celko Series for Morgan-Kaufmann Publishing
Analytics and OLAP in SQL
Data and Databases: Concepts in Practice
Data, Measurements and Standards in SQL
SQL for Smarties
SQL Programming Style
SQL Puzzles and Answers
Thinking in Sets
Trees and Hierarchies in SQL
Viewing 15 posts - 1 through 15 (of 19 total)
You must be logged in to reply to this topic. Login to reply