Stored procedure parameters with literals not working in SQL Server 2008 R2 - sql

I have a stored procedure that takes two parameters as varchar(50). The stored procedure does a few simple queries into a temp table and the returns the result set from the temp table (I removed the actual queries)
ALTER PROCEDURE [dbo].[cv_GetBooks]
#bookNumber as varchar(50),
#bookDate as varchar(50)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
--a few select statements
if #ismultiple = '0'
begin
select * from books where bookNumber = #bookNumber
and bookDate = #bookDate
and Bookname is not null
end
ELSE
Begin
select * into #temp from books
where bookNumber = #bookNumber
and bookDate = #bookDate
and Bookname is null
select * from books
where bookauthor not in (select bookauthor from #temp)
and bookNumber= #bookNumber
and bookDate= #bookDate
drop table #temp
end
END
I have this query installed on my local development machine on SQL Server 2008. I have also installed it on a two test machines running Windows Server 2003 and SQL Server 2008. The stored procedure has been working as expected.
cv_GetBooks '012345678', '06062012' --returns result set as expected
I recently moved it to a test server in another remote environment that is running Windows server 2008 and SQL Server 2008 R2. The stored procedure no longer works as expected. After running SQL Profiler I have confirmed that the same code is being executed:
cv_GetBooks '012345678', '06062012' --run on SQL server 2008 r2 returns nothing
When I removed the quotes from the query I got the expected result:
cv_GetBooks 012345678, 06062012 --run with out quotes server returns expected result set
I have since installed the same stored procedure on local version of SQL Server 2008 R2 and everything is running as expected, with the literal string quotes in place, as in the first example.
At first I thought it was an escape issue with the passed parameters but that doesn't seem correct because the passed values are do not contain any single quotes.
Having installed and had it working on so many environments, I am under the impression that this is maybe a setting in SQL Server that I am unaware of.
What could be causing the stored procedure to not return the result set with the string literals in place on the SQL Server 2008 r2 instance, but work correctly with out them there?

You did not post the table definition of table Books, but
cv_GetBooks '012345678', '06062012'
--run on SQL server 2008 r2 returns nothing
cv_GetBooks 012345678, 06062012
--run with out quotes server returns expected result set
could be caused if BookNumber and BookDate were numeric rather than varchar:
Leading zero in ints is dropped, and when converted to varchar the resulting string does not contain the leading zero.
It's also not clear how the data in your table affects the execution (IF statement!) in your code.

This might not be the exact answer, but try this as a way to finding out more about the problem. Run some basic queries (not the whole proc) in SSMS, with the parameters in place, such as:
(I'm not sure where #ismultiple comes from - doesn't seem to be declared or parameterised?)
select *
from books
where bookNumber = '012345678'
and bookDate = '06062012'
and Bookname is null
and
select *
from books
where bookNumber = 012345678
and bookDate = 06062012
and Bookname is null
Do you get the same results? What results do you get?
My suspicion is the data types: Somewhere something is being converted, and therefore not working in one environment but working in another (where the data type is different or the SQL version doesn't convert automatically). EG: 012345678 could be being converted to 12345678 if the data is stored in the table as a numeric data type. But try and isolate the behaviour without the stored procedure and/or the temp table, that might help narrow the possible causes down...

Related

Using results of one stored procedure in another stored procedure - SQL Server

Is there any way to use the results of one stored procedure in another stored procedure without using a table variable or temp table? The logic is as follows:
IF (#example = 1)
BEGIN
DECLARE #temp TABLE (Id INT);
INSERT INTO #temp
EXEC [Procedure1] #ItemId = #StockId
set #Cost = (select top 1 id from #temp)
Ideally i would like to know if there is a way to do this without having to use a temp table. Looked around online but can't find anything that works. Any advice would be great.
In general, if you want to use user-defined code in a SELECT, then it is better to phrase the code as a user-defined function rather than a user-defined procedure.
That is, procedures should be used for their side effects and functions should be used for their return values.
That said, you can use openquery (documented here) to run an exec on a linked server. The linked server can be the server you are running on.

SQL Server Stored Procedure INSERT NVARCHAR(MAX) not saving

I have a rather simple SQL Server stored procedure with 2 input parameters, a name which is nvarchar(100) and results which is nvarchar(max).
The stored procedure just does an insert - nothing more.
INSERT INTO TableX (name, results)
VALUES (#Name, #Results)
Results is a | delimited file serialized to a string. Sometimes when this stored procedure is run, the row in the table only has the name and results is blank. No SQL errors. It isn't just because of length of results because some of the calls that work are longer then some of the calls that end up empty. I did catch that some of the entries contain single quotes so I stripped out single quotes and that didn't help.
Any ideas?
Here is the stored procedure:
CREATE PROCEDURE [dbo].[tempdata_SaveMarketStatsToCache]
(#ScreenName NVARCHAR(100),
#Results NVARCHAR(MAX))
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO TempData_MarketStatsCache (MarketStatsKey, Results)
VALUES (#ScreenName, #Results)
END
Stored Procedure is called from .NET. SQLDbType.NVarchar with length of -1
UPDATE: I suspect it is the size of the string being passed. The smallest string that is failing is just under 250K characters. This is OK for NVARCHAR(max), but it seems that something happens during the INSERT.
UPDATE 2: Turns out it was an issue with SQL Server Managment Studio. I was right clicking on table and choosing edit 200 rows. That showed the column as empty for the rows with the large results (over 200K characters). If I simply ran a query the column values showed.
Turns out it was a SQL Server Management Studio issue making it seem like data wasnt inserted. See Update 2 in the question.

How to execute sql query when debugging a stored procedure

I'm debugging a stored procedure on SQL Server 2008 and I have this:
INSERT INTO #tempTable (ID, Name)
SELECT ID, Name FROM dbo.MYTABLE WHERE dbo.MYTABLE.Old >= 15
How can I view the data into #tempTable on Debug time?
In SQL Server Management Studio, you can't execute query directly while debugging stored procedure, and that's still not implemented(I think). You can only view the local variables value in Local Debug Window.
There are some work around to see temp table values while in Debugging mode:-
1) In the stored procedure, after insert data into #temptable, add this line of code to get temptable values in xml table varriable where you want to see temptable values. Then you can check the values in Local Debug window in xml format
--inserting data into temp table
INSERT INTO #tempTable (ID, Name)
SELECT ID, Name FROM dbo.MYTABLE WHERE dbo.MYTABLE.Old >= 15
--to see records of temp table
DECLARE #temptable XML
SET #temptable = (SELECT * FROM ##temptable FOR XML AUTO)
2) You can convert local temp table(#temptable) to global temptable(##temptable), so when you insert date in temp table, you can open new query window, and able to see global temp table records using select query.
This blog post describes how to access a temporary table from another session:
http://web.archive.org/web/20180409190701/http://sqlblog.com:80/blogs/paul_white/archive/2010/08/14/viewing-another-session-s-temporary-table.aspx
Alternative you can use two ## in the table name to make the table globally accessible from other sessions: ##tempTable (The table might be locked for reading while your insert is running)
Even though SQL Server Management Studio has some debugging functions , but I find them pretty useless.
I don't think there are any debugging tools out there for SQL Server like Visual Studio, which will give you a step by step information at runtime.
The way normally developers debug sql server code is to use print statement, for stored procedures take the sp definition out declare a variable for each parameter that procedure expects , hardcode the values for variables and execute smaller logical blocks of code to see what's going on where.

Execute section of SQL based on presense of a linked server

I'm trying to write a query that can run on different servers. One way I'm trying to detect which server i'm on is the presense of a certain linked server (i.e. Server1 will have a link to Server2 and vice versa).
Trouble is, I can't get SQL Server to ignore/skip the code that runs on the non-existant linked server. There are two nearly identical sections of code, one which uses the Linked Server1 and one which does not (because it's running on Server1 already).
drop table #origdates
if exists(select 1 from sys.servers where name = N'Server1')
BEGIN
Select * into #origdates from openquery([Server1],'Select accounts, dates from table1')
END
if not exists(select 1 from sys.servers where name = N'Server1')
BEGIN
Select accounts, dates into #origdates from table1
END
If I execute the individual sections, everything is fine; the code either executes or not as specified, but the moment I run the entire thing together it's as if the server ignores the if exists section, with an error like:
Could not find server 'Server1' in sys.servers. Verify that the correct server name was specified. If necessary, execute the stored procedure sp_addlinkedserver to add the server to sys.servers.
The reason I'm doing this is so I don't have to maintain two identical scripts with two separate begginning sections.
Using ELSE in place of the second if not exists line results in the server complaining that the #origdates table already exists, even if a drop table command is issued right before the line of the select into command.
Using different table names returns the error to the 'Could not find server' message, despite that it's not even supposed to be executing that code at all...
Try this, SQL is trying to validate the OPENQUERY, but it can't because [Server1] is not a valid linked server. Hiding the OPENQUERY in a variable should fix it.
Note, you need to pass FROM db.owner.table in an OPENQUERY, not just FROM table
declare #sql nvarchar(max)
if object_id('tempdb..#origdates') is not null
drop table #origdates
create table #origdates (accounts int, dates datetime)
if exists(select 1 from sys.servers where name = N'Server1')
BEGIN
set #sql='insert into #origdates Select * from openquery([Server1],''select accounts, dates from db.dbo.table1'')'
exec(#sql)
END
else
BEGIN
insert into #origdates Select accounts, dates from table1
END

Query times out in .Net SqlCommand.ExecuteNonQuery, works in SQL Server Management Studio

Update: Problem solved, and staying solved. If you want to see the site in action, visit Tweet08
I've got several queries that act differently in SSMS versus when run inside my .Net application. The SSMS executes fine in under a second. The .Net call times out after 120 seconds (connection default timeout).
I did a SQL Trace (and collected everything) I've seen that the connection options are the same (and match the SQL Server's defaults). The SHOWPLAN All, however, show a huge difference in the row estimates and thus the working version does an aggressive Table Spool, where-as the failing call does not.
In the SSMS, the datatypes of the temp variables are based on the generated SQL Parameters in the .Net, so they are the same.
The failure executes under Cassini in a VS2008 debug session. The success is under SSMS 2008 . Both are running against the same destination server form the same network on the same machine.
Query in SSMS:
DECLARE #ContentTableID0 TINYINT
DECLARE #EntryTag1 INT
DECLARE #ContentTableID2 TINYINT
DECLARE #FieldCheckId3 INT
DECLARE #FieldCheckValue3 VARCHAR(128)
DECLARE #FieldCheckId5 INT
DECLARE #FieldCheckValue5 VARCHAR(128)
DECLARE #FieldCheckId7 INT
DECLARE #FieldCheckValue7 VARCHAR(128)
SET #ContentTableID0= 3
SET #EntryTag1= 8
SET #ContentTableID2= 2
SET #FieldCheckId3= 14
SET #FieldCheckValue3= 'igor'
SET #FieldCheckId5= 33
SET #FieldCheckValue5= 'a'
SET #FieldCheckId7= 34
SET #FieldCheckValue7= 'a'
SELECT COUNT_BIG(*)
FROM dbo.ContentEntry AS mainCE
WHERE GetUTCDate() BETWEEN mainCE.CreatedOn AND mainCE.ExpiredOn
AND (mainCE.ContentTableID=#ContentTableID0)
AND ( EXISTS (SELECT *
FROM dbo.ContentEntryLabel
WHERE ContentEntryID = mainCE.ID
AND GetUTCDate() BETWEEN CreatedOn AND ExpiredOn
AND LabelFacetID = #EntryTag1))
AND (mainCE.OwnerGUID IN (SELECT TOP 1 Name
FROM dbo.ContentEntry AS innerCE1
WHERE GetUTCDate() BETWEEN innerCE1.CreatedOn AND innerCE1.ExpiredOn
AND (innerCE1.ContentTableID=#ContentTableID2
AND EXISTS (SELECT *
FROM dbo.ContentEntryField
WHERE ContentEntryID = innerCE1.ID
AND (ContentTableFieldID = #FieldCheckId3
AND DictionaryValueID IN (SELECT dv.ID
FROM dbo.DictionaryValue AS dv
WHERE dv.Word LIKE '%' + #FieldCheckValue3 + '%'))
)
)
)
OR EXISTS (SELECT *
FROM dbo.ContentEntryField
WHERE ContentEntryID = mainCE.ID
AND ( (ContentTableFieldID = #FieldCheckId5
AND DictionaryValueID IN (SELECT dv.ID
FROM dbo.DictionaryValue AS dv
WHERE dv.Word LIKE '%' + #FieldCheckValue5 + '%')
)
OR (ContentTableFieldID = #FieldCheckId7
AND DictionaryValueID IN (SELECT dv.ID
FROM dbo.DictionaryValue AS dv
WHERE dv.Word LIKE '%' + #FieldCheckValue7 + '%')
)
)
)
)
Trace's version of .Net call (some formatting added):
exec sp_executesql N'SELECT COUNT_BIG(*) ...'
,N'#ContentTableID0 tinyint
,#EntryTag1 int
,#ContentTableID2 tinyint
,#FieldCheckId3 int
,#FieldCheckValue3 varchar(128)
,#FieldCheckId5 int
,#FieldCheckValue5 varchar(128)
,#FieldCheckId7 int
,#FieldCheckValue7 varchar(128)'
,#ContentTableID0=3
,#EntryTag1=8
,#ContentTableID2=2
,#FieldCheckId3=14
,#FieldCheckValue3='igor'
,#FieldCheckId5=33
,#FieldCheckValue5='a'
,#FieldCheckId7=34
,#FieldCheckValue7='a'
It is not your indexes.
This is parameter-sniffing, as it usually happens to parametrized stored procedures. It is not widely known, even among those who know about parameter-sniffing, but it can also happen when you use parameters through sp_executesql.
You will note that the version that you are testing in SSMS and the version the the profiler is showing are not identical because the profiler version shows that your .Net application is executing it through sp_executesql. If you extract and execute the full sql text that is actually being run for your application, then I believe that you will see the same performance problem with the same query plan.
FYI: the query plans being different is the key indicator of parameter-sniffing.
FIX: The easiest way to fix this one assuming it is executing on SQL Server 2005 or 2008 is to add the clause "OPTION (RECOMPILE)" as the last line of you SELECT statement. Be forewarned, you may have to execute it twice before it works and it does not always work on SQL Server 2005. If that happens, then there are other steps that you can take, but they are a little bit more involved.
One thing that you could try is to check and see if "Forced Parameterization" has been turned on for your database (it should be in the SSMS Database properties, under the Options page). To tunr Forced Parameterization off execute this command:
ALTER DATABASE [yourDB] SET PARAMETERIZATION SIMPLE
I ran into this situation today and the fix that solved my problem is to use WITH (NOLOCK) while doing a select on tables:
Eg: If your stored proc has T-SQL that looks like below:
SELECT * FROM [dbo].[Employee]
Change it to
SELECT * FROM [dbo].[Employee] WITH (NOLOCK)
Hope this helps.
I've had off-hours jobs fubar my indexes before and I've gotten the same result as you describe. sp_recompile can recompile a sproc... or, if that doesn't work, the sp_recompile can be run on the table and all sprocs that act on that table will be recompiled -- works for me every time.
I ran into this problem before as well. Sounds like your indexes are out of whack. To get the same behavior in SSMS, add this before the script
SET ARITHABORT OFF
Does it timeout as well? If so, it's your indexing and statistics
It's most likely index-related. Had a similar issue with .Net app vs SSMS (specifically on a proc using a temp table w/ < 100 rows). We added a clustered index on the table and it flew from .Net thereafter.
Checked and this server, a development server, was not running SQL Server 2005 SP3. Tried to install that (with necessary reboot), but it didn't install. Oddly now both code and SSMS return in subsecond time.
Woot this is a HEISENBUG.
I've seen this behavior before and it can be a big problem with o/r mappers that use sp_executesql. If you examine the execution plans you'll likely find that the sp_executesql query is not making good use of indexes. I spent a fair amount of time trying to find a fix or explanation for this behavior but never got anywhere.
Most likely your .Net programs pass the variables as NVARCHAR, not as VARCHAR. Your indexes are on VARCHAR columns I assume (judging from your script), and a condition like ascii_column = #unicodeVariable is actually not SARG-able. The plan has to generate a scan in this case, where in SSMS would generate a seek because the variable is the right type.
Make sure you pass all your string as VARCHAR parameters, or modify your query to explicitly cast the variables, like this:
SELECT dv.ID
FROM dbo.DictionaryValue AS dv
WHERE dv.Word LIKE '%' + CAST(#FieldCheckValue5 AS VARCHAR(128)) + '%'