I have a stored proecdure like below:
#userInput int
as
declare isSuperUser int
declare IDs table(
recordID int
);
set isSuper = select isSuper from [User]
if(#isSuper = 1)
Begin
insert into recordID select * from TableA
End
else
Begin
insert into recordID select * from TableB
End
select * from recordID
And I would like to add "set noCount on" on every query, so the question is: is the performance in store procedureA equivalent to store procedureB?
store procedureA :
#userInput int
as
declare isSuperUser int
declare IDs table(
recordID int
);
set noCount on
set isSuper = select isSuper from [User]
if(#isSuper = 1)
Begin
insert into recordID select * from TableA
End
else
Begin
insert into recordID select * from TableB
End
select * from recordID
set noCount off
store procedureB:
#userInput int
as
declare isSuperUser int
declare IDs table(
recordID int
);
set noCount on
set isSuper = select isSuper from [User]
set noCount off
if(#isSuper = 1)
Begin
set noCount on
insert into recordID select * from TableA
set noCount off
End
else
Begin
set noCount on
insert into recordID select * from TableB
set noCount off
End
set noCount on
select * from recordID
set noCount off
SET NOCOUNT ON prevents the sending of DONE_IN_PROC messages to the client for each statement in a stored procedure. For stored procedures that contain several statements that do not return much actual data, or for procedures that contain Transact-SQL loops, setting SET NOCOUNT to ON can provide a significant performance boost, because network traffic is greatly reduced.
TechNet
While storedProcedure is executing , there is no point of sending data back to client, setting noCount On increases performance as it reduces network traffic .
In your Store Procedure B you are switching NoCount on to off which increases network traffic.
Related
I'm going to create different temp tables depending on the #selection parameter I get, and then I want to return the table I created.
I actually wanted to do it with the function, but I got an error for variable parameter tables. The sql procedur I wrote is as follows:
ALTER PROCEDURE [dbo].[Report]
(#Id BIGINT = 55,
#selection INT)
AS
BEGIN
IF #selection=1
BEGIN
Declare #tep_table table (Id int
,Name varchar(250)
,CreateTime datetime
,UpdateTime datetime
,UpdatedBy varchar(250)
,Deleted bit
)
Insert into #tep_table
Select * from User
END
IF #selection=1
BEGIN
Declare #tep_table2 table (Id int
,CreateTime datetime
,UpdateTime datetime
,UpdatedBy varchar(250)
,Deleted bit
)
Insert into #tep_table2
Select * from Client
END
IF #selection=1
BEGIN
RETURN #tep_table
END
ELSE
BEGIN
RETURN #tep_table2
END
END
I am getting this error:
Must declare the scalar variable "#tep_table"
Personally I would turn this into three procedures to avoid the performance problems faced with multiple execution paths.
Something like this.
ALTER Procedure [dbo].[Report]
(
#Id bigint = 55 --not sure what the point of this parameter is as it wasn't used anywhere in the sample code
, #selection int
) AS
set nocount on;
IF #selection = 1
exec GetUserData;
IF #selection = 2
exec GetClientData;
GO
create procedure GetUserData
AS
set nocount on;
Select * --would prefer to use column names here instead of *
from [User];
GO
create procedure GetClientData
AS
set nocount on;
Select * --would prefer to use column names here instead of *
from Client;
GO
I have a stored procedure that looks like this:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE Guests_Load
#Id AS Varchar(30)
AS
SET NOCOUNT ON
SELECT *
FROM Guests
WHERE HotelId = #Id
SELECT
GroupId,
HotelName,
FROM
HotelView(NOLOCK)
WHERE
HotelId = #Id
GO
Now, I want to create a new result set by writing another SELECT statement.
However, I want the groupId that is returned from the second SELECT. How do I do this? I tried:
DECLARE #hotelId int;
SELECT
#hotelId = GroupId,
HotelName,
FROM
HotelView(NOLOCK)
WHERE
HotelId = #Id
but I get an error saying
A SELECT statement that assigns a value to a variable must not be combined with data-retrieval operations
A simple solution is just to run the query twice:
CREATE PROCEDURE Guests_Load (
#Id AS Varchar(30)
) AS
BEGIN
SET NOCOUNT ON;
SELECT *
FROM Guests
WHERE HotelId = #Id;
SELECT GroupId, HotelName
FROM HotelView
WHERE HotelId = #Id;
DECLARE #GroupId int;
SELECT #GroupId = GroupId
FROM HotelView
WHERE HotelId = #Id;
END;
Personally, I am not a fan of stored procedures printing out tables. So, I would be inclined to have all the SELECTs use only variables. But if you want the print-out, then one method is to run the code twice.
I have a trigger ,but I need to get the updated record's primary key (like as inserting the data SELECT #Id= ##IDENTITY) thus, I can pass it to where condition. How can I do that?
ALTER TRIGGER [dbo].[CariBakiyeBorcAktar]
ON [dbo].[BakimKartiDegisenParcalar]
AFTER UPDATE
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
DECLARE #Id int
DECLARE #CariId int
DECLARE #SId int
DECLARE #MId int
declare #Tutar decimal
declare #Bakiye decimal
declare #s decimal = 0
DECLARE #ParcaId int
--how I can I get the last updateed record Identity like this??
--and pass it to update query as a where condition
SELECT #Id= ##IDENTITY
set #SId=(select SId from CariBakiye where Id =#Id)
select #CariId=tblk.CariId ,#MId=tblk.MId, #SId= tblk.SId,#Tutar=tblk.Tutar from (
SELECT tbl.CariId , tbl.MId,tbl.SId,tbl.Tutar from (select cb.MId,SUM(bk.Tutar) as Tutar,bk.SId,cb.Id as CariId FROM [BakimKartiDegisenParcalar] bk
join CariBakiye cb on cb.SId=bk.SId
where bk.SId =cb.SId group by bk.SId,cb.MId,cb.Id ) as tbl
) as tblk where SId = #SId
set #Bakiye = #s-#Tutar
update CariBakiye set Borc=#Tutar,Bakiye=#Bakiye where Id=#CariId
print #Id
-- Insert statements for trigger here
END
As Martin said, you have to understand that SQL Server triggers are per statement, not per row. So in context of your trigger you have two tables - inserted and deleted, where you could find all information about data updated. If you really want to do per row processing, you could use cursor:
ALTER TRIGGER [dbo].[CariBakiyeBorcAktar] ON [dbo].[BakimKartiDegisenParcalar]
AFTER UPDATE
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
DECLARE #Id int
DECLARE #CariId int
DECLARE #SId int
DECLARE #MId int
declare #Tutar decimal
declare #Bakiye decimal
declare #s decimal = 0
DECLARE #ParcaId int
declare tr_cursor cursor local fast_forward for
select ID from inserted
while 1 = 1
begin
fetch tr_cursor into #Id
if ##fetch_status <> 0 break
set #SId=(select SId from CariBakiye where Id =#Id)
select #CariId=tblk.CariId ,#MId=tblk.MId, #SId= tblk.SId,#Tutar=tblk.Tutar from (
SELECT tbl.CariId , tbl.MId,tbl.SId,tbl.Tutar from (select cb.MId,SUM(bk.Tutar) as Tutar,bk.SId,cb.Id as CariId FROM [BakimKartiDegisenParcalar] bk
join CariBakiye cb on cb.SId=bk.SId
where bk.SId =cb.SId group by bk.SId,cb.MId,cb.Id ) as tbl
) as tblk where SId = #SId
set #Bakiye = #s-#Tutar
update CariBakiye set Borc=#Tutar,Bakiye=#Bakiye where Id=#CariId
print #Id
-- Insert statements for trigger here
end
close tr_cursor
deallocate tr_cursor
END
A MS SQL insert trigger causes some grief as it returns a result. Is there a way to disable any result from being sent? I've used 'set nocount on', but that doesn't seem to do much...
create trigger tr_insert_raw_data
on raw_data
instead of insert
as
begin
set nocount on
declare #query varchar(max);
declare #rev int;
declare #id int;
declare #oldrev int;
declare #contextinfo VARBINARY(128)
select #contextinfo = context_info()
if #contextinfo = 0x00001
begin
insert into raw_data select * from inserted
return
end
select * into #query from inserted
set #id = (select count(distinct id) from raw_data);
set #id += 1;
insert into revisions (username, hostname, ts) values (SYSTEM_USER, HOST_NAME(), GETDATE())
set #rev = (select max(id) from revisions);
select #oldrev = revision_id from inserted;
if #oldrev is null set #oldrev=#rev-1;
select * into #inserted from inserted
update #inserted set revision_id = #rev, id = #id
select * from #inserted
insert into raw_data select * from #inserted
insert into edges (a, b) values (#oldrev, #rev)
end
what kind of a result are you getting?
After a quick review of your query my first thought is that you're getting results due to the
select * from #inserted
line you have (third line from bottom). This line tells me that you are requesting results which is probably why you're getting some?
If you do need values selected from a table to modify or custom select out of, perhaps CTE's will help you out? (Common Table Expressions)
I have to implement SELECT ... FROM ... WHERE .. IN query in my stored procedure.
Below is the code from my stored procedure
ALTER PROCEDURE [dbo].[SP_GetQuestionSetMultiCat]
-- Add the parameters for the stored procedure here
#PIN varchar(50),
#CatIds varchar(50),
#Range int,
#Que_Type varchar(50)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
declare #qtId as int;
select #qtId = Que_Type_Id from dbo.QuestionType_Tbl where Que_Type=#Que_Type;
-- Insert statements for procedure here
Select Top(#Range)
QId,
Que_Type_Id,
Que_Level_Id,
Que_Category_Id,
Que,
Opt1,
Opt2,
Opt3,
Opt4,
Ans
From
dbo.Que_Tbl
Where
(Que_Category_Id in (cast(#CatIds as varchar)))
and (Que_Type_Id=#qtId)
and (Qid not in (Select Que_Id From dbo.UserQuestion_Mapping where PIN=#PIN and Que_typeID=#qtId))
END
Look at the where condition. The Que_Category_Id is int type. What i want to perform is -
Where Que_Category_Id in (1,2,3,4)
The in values i m passing is a string converted from my C# code.
When I am executing this query like -
exec SP_GetQuestionSetMultiCat '666777','4,5,6',5,'Practice'
it is generating an error -
Conversion failed when converting the varchar value '{4,5,6}' to data type int.
Can anybody help me out how to solve this problem.
Thanks for sharing your valuable time.
1)Conversion failed when converting the varchar value '{4,5,6}' to data type int.
The reason of this error is data type precedence. INT data type has "higher" precedence than VARCHAR data type (16-INT vs. 27-VARCHAR).
So, SQL Server is trying to convert '{4,5,6}' to INT and not vice versa.
2) Instead, I would convert #CatIds to XML and then to a table variable (#IDs) using nodes(...) method:
SET ANSI_WARNINGS ON;
DECLARE #CatIds VARCHAR(50) = '4,5,6';
DECLARE #x XML;
SET #x = '<node>' + REPLACE(#CatIds, ',', '</node> <node>') + '</node>';
DECLARE #IDs TABLE
(
ID INT PRIMARY KEY
);
INSERT #IDs(ID)
SELECT t.c.value('.', 'INT')
FROM #x.nodes('/node') t(c);
--Test
SELECT *
FROM #IDs
3) The next step is to rewrite the query using IN (SELECT ID FROM #IDs) instead of in (cast(#CatIds as varchar)):
SET ANSI_WARNINGS ON;
ALTER PROCEDURE [dbo].[SP_GetQuestionSetMultiCat]
-- Add the parameters for the stored procedure here
#PIN varchar(50),
#CatIds varchar(50),
#Range int,
#Que_Type varchar(50)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
declare #qtId as int;
select #qtId = Que_Type_Id from dbo.QuestionType_Tbl where Que_Type=#Que_Type;
--Start: New T-SQL code
DECLARE #x XML;
SET #x = '<node>' + REPLACE(#CatIds, ',', '</node> <node>') + '</node>';
DECLARE #IDs TABLE
(
ID INT PRIMARY KEY
);
INSERT #IDs(ID)
SELECT t.c.value('.', 'INT')
FROM #x.nodes('/node') t(c);
--End
-- Insert statements for procedure here
Select Top(#Range)
QId,
Que_Type_Id,
Que_Level_Id,
Que_Category_Id,
Que,
Opt1,
Opt2,
Opt3,
Opt4,
Ans
From
dbo.Que_Tbl
Where
--The search condition is rewritten using IN(subquery)
Que_Category_Id in (SELECT ID FROM #IDs)
and (Que_Type_Id=#qtId)
and (Qid not in (Select Que_Id From dbo.UserQuestion_Mapping where PIN=#PIN and Que_typeID=#qtId))
END
4) Call stored procedure:
exec SP_GetQuestionSetMultiCat '666777','4,5,6',5,'Practice'