CREATE PROCEDURE Testing1
#Varaible nvarchar(50),
#value integer
AS
BEGIN
DECLARE #SUMM FLOAT
SET #SUMM=(#value*2.38/7.456)*2
PRINT #Varaible
PRINT 'EXPENSES IS'
PRINT #SUMM
END
Output is:
PETER
EXPENSES IS
24.2597
The above is my code where I am passing a single input parameter.
If I want to pass multiple values like peter,robber,licoln,mat
#varaible peter,robber,licoln,mat
#value 37 45 66 77
is it possible in SQL??
If you're only sending a few values in your delimited strings, I would suggest simply using the proper datatypes and calling the stored procedure a few times with individual values.
If, however, your delimited strings might contain hundreds or thousands of discrete values, then calling a proc that many times could be costly in terms of performance, especially if you can't send them all in one batch (I'm sure you want to use parameters rather than a giant concatenated command). If this is the case, you have a few options:
Use Table Valued Parameters. This is like passing arrays as arguments to your proc.
Pass XML to your proc, then shred and process it within the procedure.
Insert your data to staging/temp tables, then call the procedure to operate on those tables.
Take a step back and see if it makes sense to do more processing in your app. DB code usually doesn't scale nearly as well as app code.
Send these delimited strings to your proc, split/parse them, then loop over the results in SQL. This seems to be what you're asking about and is possibly the least elegant option, even though it's one of the more popular ways to abuse a relational database.
The table valued parameters approach seems very 'approachable', but is only available as of MSSQL 2008. If you are still stuck with MSSQL 2005 then, maybe, the temporary table approach works best for you?
Your code could look something like:
-- define your stored procedure
CREATE PROC sptest1 AS
BEGIN
-- do some stuff with #tmp, like join it to other tables
-- and UPDATE values in these tables with it!
-- or simply list a processed version of #tmp:
SELECT nam,val*(2.38/7.456)*2 FROM #tmp
END
-- prepare input values by creating a temporary table on the fly
SELECT 'Peter' nam,23 val INTO #tmp
UNION ALL SELECT 'Paul',27
UNION ALL SELECT 'Harry',16
UNION ALL SELECT 'Mary-Ann',45;
-- and call the procedure:
EXEC sptest1
So, your frontend will have to build the SELECT ... INTO #tmp ... string. After that the rest of the processing can be done inside your stored procedure.
Related
I have two versions of a stored proc and want to make sure that their outputs are exactly the same. My unit tests and functional tests do verify that the two versions are the same. However before using the newer version of the proc on a live environment I want to make sure that they match.
I am trying to do the following on a copy of the live DB:
Start a transaction.
Call stored procedure sproc_v1 (internally the proc modifies table T1).
Select * into T1_v1 from T1 (with a condition to filter out those rows affected by the sproc_v1)
Rollback the transaction (so that I have same initial conditions for running V2
Call stored procedure sproc_v2
Select * into T1_v2 from T1
Well obviously after step 3 - the values in T1_v1 are also rolled back. May be I can dump the data into a file and compare the files. Was wondering if there is another way to do this kind of matching.
How big is your result set?
One approach might be to declare xml variables
DECLARE #xml1 XML, #xml2 XML;
... and use
SET #xml1=(SELECT ... FOR XML RAW) --without the "INTO SomeTable"! Same with `#xml2`
At the end you can use
SELECT CASE WHEN CAST(#xml1 AS NVARCHAR(MAX))=CAST(#xml2 AS NVARCHAR(MAX)) THEN ...`
Make sure, that there are no timestamps or other variable content, which would disturb of course...
UPDATE
You might use a declared table variable, which lives as long as your job lives and is not affected by the rollback:
Instead of your SELECT * INTO SomeTable you use INSERT INTO #tableVariable (col1, col2, ...) SELECT col1, col2, ... FROM ....
Just use the existing declaration of your table to create the table variable. No need to type in all columns manually...
I always use excel for this. Paste the results of the first stored procedure in sheet 1, the results of the second stored procedure in the second sheet and compare the values in the third sheet.
I have a stored procedure which returns a few columns from a SELECT. Now I need to grab 2 columns out of those columns in my new stored procedure and use them.. I am trying to do this using EXEC method. Is it possible to do this?
Ex : Original stored procedure:
CREATE PROCEDURE myBaseProcedure
#stId INT
AS
BEGIN
SELECT Name,
Address,
StudentId,
Grade
FROM Student
WHERE StudentId = #stId
END
New stored procedure:
CREATE PROCEDURE myNextProcedure
BEGIN
EXEC myBaseProcedure 19 -- Here I need to grab only StudentId and Name??
END
Given that you cannot dump to a temp table or table variable since the base stored procedure might sometimes add columns, there are three approaches that would do this:
You can effectively SELECT from a stored procedure using either OPENROWSET or OPENQUERY
You can use SQLCLR to create a table-valued function that executes the procedure, returns a struct of just the fields that you want, which will be the only fields that you read or "get" from the SqlDataReader.
You can use SQLCLR to create a stored procedure that executes the procedure to get a SqlDataReader, and instead of returning the SqlDataReader to SqlContext.Pipe.Send(), you would use SendResultsStart, SendResultsRow, and SendResultsEnd. You would create a SqlDataRecord of just the fields you wanted, and those would also be the only fields that you read or "get" from the SqlDataReader. While this still leaves you with a stored procedure, the filtering of the fields is done within the CLR-based proc so the output is guaranteed to be just the fields you want, regardless of how the result set structure of the base stored procedure changes. In this way you could create a local temp table to dump the results to, which would be better for JOINing to other tables. This method also allows for you to pass in a list of fields to the CLR-based stored procedure that would be parsed and used as the fields to dynamically construct the SqlDataRecord with as well as to dynamically determine which fields to get from the SqlDataReader. That would be a little more complicated but also quite a bit more flexible :).
You don't need to create a new stored procedure for this, you can integrate the stored proc call in a simple query using OpenQuery or use a temporary table.
Using OPENQUERY
SELECT Name,
Address
FROM OPENQUERY(ServerName, 'EXEC myBaseProcedure 19')
-- WHERE your_field = expected_value --> if you need to add filters
Using Temp table
Declare #MyTempTable Table (columns definitions)
Insert #MyTempTable Exec myBaseProcedure 19
Select Name,
Address
FROM #MyTempTable
I am using a stored procedure to insert records into a table. And do this at least 12 times in a loop to insert multiple records which is very inefficient.
here is the procedure as CREATED
Create PROC [dbo].[SP_INSERT_G_SAMPLING]
#GameID INT,
#ScoreID INT
as
begin
INSERT INTO GAMESCORE (GAMEID, SCOREID) VALUES
(#GameID, #ScoreID)
end
I pass on the values ex(1,3) and loop with more values from the website.
I want to however pass on all the values at one time like (1,3),(4,5),(8,9)
and then alter the above procedure to receive and insert multiple rows.
ALTER PROC [dbo].[SP_INSERT_G_SAMPLING]
#totalinsert nvarchar(Max)
INSERT INTO GAMESCORE (GAMEID, SCOREID) VALUES
(#totalinsert)
with #totalinsert being like (1,3),(4,5),(8,9) pushed from the webpage.
any help is greatly appreciated
What you're going to have to do is write a table valued function which accepts the multi-value string and breaks it out into a table object. If you can change your source to use a record delimiter instead of having comma sets it would be slightly easier to process. An example of that would look like this.
The below is pure psuedo and has not been validated in any way, just meant to give you a rough idea of where to go.
ex: #TotalInsert = 1,2|4,5|8,9
DECLARE #Results TABLE
(
value1 INT,
value2 INT
)
DECLARE #setlist VARCHAR(max);
WHILE Len(#TotalInsert) > 0
BEGIN
SET #setlist = LEFT(#totalinsert, Charindex('|', #totalinsert))
INSERT INTO #results
SELECT LEFT(#setlist, Charindex(',', #setlist) - 1),
RIGHT(#setlist, Charindex(',', Reverse(#setlist)) + 1)
SET #totalinsert = RIGHT(#totalinsert, Len(#totalinsert) - Len(#setlist))
END
I'm assuming you're using .NET for your website since you're also using SQL Server.
Have a look at table valued parameters, this page also includes a nice example of how to use the table valued parameters in .NET.
Check here for a better example of making a stored procedure with a table valued parameter in T-SQL.
Here is the full discussion:
http://www.sommarskog.se/arrays-in-sql-2005.html#XMLlist%20of%20values
Personally, I sent xml to the stored procedure, I "shred it" into #variable or #temp tables, then I do my INSERT/UPDATE/MERGE/DELETE from there.
Here is a fuller discussion on xml-shredding.
http://pratchev.blogspot.com/2007/06/shredding-xml-in-sql-server-2005.html
My personal trick is to create a strong dataset, populate the strong dataset with rows, and use the ds.GetXml() to send the xml down to the TSQL. With a strong dataset, I get strong-typing when populating the values. But at the end of the day, dataset is just some super fancy xml.
I have 7 different stored procedures that take in a number of parameters and insert data into 7 different tables.
I am now creating a main stored procedure to execute these 7 procedures with all of the data they need. All of the data they need is ONE table (CommonImport).
Should I take all of the parameters I need in this main stored procedure?
Or
Only take in the ID of the row that needs to be inserted into these 7 separate tables and get the data directly from the table.
I think the second option is best. BUT, how do I set all the variables in the main stored procedure to all of the data from the (CommonImport) table?
Essentially, how do I set a bunch of declared variables to the values from a specific row in the CommonImport table?
Thanks
Passing an ID:
The benefit here is that you simplify all the interfaces to your stored procedures.
This makes it easier to code against. If you end up calling the SP from speveral places, you just need to use a single parameter, rather than loading and passing several parameters.
Passing n Variables:
Then benefit here is that you 'decouple' your Stored Procedures from the holding table.
This means that you could simply call the stored procedures directly, without having any data in the table. This may be useful in the future, if data arrives in a new way, or for unit testing, etc.
Which is best:
I don't think that there is a straight answer to this, it's more a case of preference and opinion.
My opinion is that the less tightly coupled things are, the better. It's more flexible in the face of changes.
The way I'd do it is as follows...
CREATE PROCEDURE main_by_variable #v1 INT, #v2 INT, ...
BEGIN
EXEC sub_part_1 #v1, #v3
EXEC sub_part_2 #v2
EXEC sub_part_3 #v2, #v3
...
END
CREATE PROCEDURE main_by_id #id INT AS
BEGIN
DECLARE
#v1 INT,
#v2 INT,
...
SELECT
#v1 = field1,
#v2 = field2
FROM
holding_table
WHERE
id = #id
EXEC main_by_variable #v1, #v2, ...
END
GO;
By having the main_by_variable procedure, you have the felxibility, such as testing all the sub procedures, without actually having to enter any data into the holding table. And that flexibility is part of the sub procedures as well.
But, for convenience, you may find that using main_by_id is more tidy. As this is just a wrapper around main_by_variable, all you are doing is encapsulating a single step in the process (getting the data out of the table).
It also allows you to put a transaction around the data gathering part, and delete the data out of the table. Or many other options. It's flexible, and I like flexible.
I would suggest accepting all variables as parameters and define default values for them, so SP users can use it either with single ID parameter or with an other as weel by specifying those directly
CREATE PROCEDURE MainSP
#ID int,
#CustomParameter varchar(10) = NULL,
#CustomParameter1 DateTime = NULL,
...
In this way SP would be pretty flexible
Is it possible to work with the returned datasets from a stored procedure? Basically I have a stored procedure (lets call it SP_1) and it calls another stored procedure (lets call it SP_2). SP_2 has 5 or so select statements. What I want to do is handle each select statement within SP_1. Basically to manipulate the data or whatever, but I do not know how to get it.
Let me show what im doing and that may make things clearer
CREATE PROCEDURE [dbo].[usp_1]
AS
exec usp_2
//How do I store the multiple select statements results in this stored proc?
In order to work, all the SELECTs within SP_2 will need to return the same number of compatible columns. If one returns 2 columns, another returns 5, and another returns 10, then it won't work.
If each SELECT does return the same number of columns, and the datatypes are consistent then you should be good to go using this approach in SP_1
CREATE TABLE #test (Col1 VARCHAR(10), Col2 VARCHAR(10))
INSERT #test
EXECUTE SP2 -- all resultsets return 2 VARCHAR columns
-- Now use #test which should contain all the combined results from SP2
However, if they all return different columns then you can't do it. You'd need to break each individual select into it's own sproc and call each one independently. SP2 would change to call those sub sprocs too.