SQL Server multiple EXEC Stored procedure and C# with XML - c#

I have a few stored procedures which I am trying to call from another stored procedure like this:
SET NOCOUNT ON;
DECLARE #x1 XML;
DECLARE #x2 XML;
DECLARE #x3 XML;
EXEC p1 0, 2, #x1 OUTPUT
EXEC p2 0, 0, #x2 OUTPUT
EXEC p3 1, #x3 OUTPUT
DECLARE #x XML;
SET #x = (SELECT #x1, #x2, #x3) FROM XML PATH('root')
When I execute procedure in management studio, it returns 4 outputs in the result window. #x1, #x2, #x3 and #x respectively.
But when try to read this output in .NET C# (xmlReader = cmd.ExecuteXmlReader();), it only reads the first xml from #x1.
I don't know how can I limit the stored procedure to only return the output of #x. Or do I need something else?
Any help will be appreciated
EDIT:
Here is the first procedure:
#VersionID AS INT,
#xml AS XML = NULL OUTPUT
SET NOCOUNT ON;
SET #xml = (
SELECT
COALESCE(VersionID, 0) AS VersionID,
COALESCE(VersionName, '') AS VersionName
FROM
Versions v
WHERE
v.VersionID = #VersionID
FOR XML PATH ('Version')
);
SELECT #xml;
The rest look exactly the same with different tables

The SELECT #xml; at the end of the Stored Proc is being returned as the first result set (out of several result sets). You should remove that SELECT as you are returning the value via OUTPUT param.
If the SELECT #xml; is required by other callers of this proc, then you can add another input param for #SelectOutput BIT = 1 and wrap the SELECT at the end around a test of the new input param, such as:
IF (#SelectOutput = 1)
BEGIN
SELECT #xml;
END
Then in your outer proc (as shown at the top of your question), pass in a 0 for the new input param. No other callers of the proc need to be updated since the default value is to operate as it currently does.
EXEC p1 0, 2, #x1 OUTPUT, 0
Repeat the above steps (i.e. either remove final SELECT or at least wrap in an IF condition based on new, optional input param) for all sub-proc calls (i.e. p1, p2, and p3).
Finally:
Be sure to set the value of #x correctly. What is posted in the question doesn't work (might even cause the proc to error) and should be: SET #x = (SELECT #x1, #x2, #x3 FOR XML PATH('root'))
Make sure to actually do a SELECT #x in that outer proc as simply setting #x (assuming that it is an OUTPUT param) isn't a result set and hence not what XmlReader is looking for.

Related

Execute SQL arithmetic stored as string (stored procedure? c#?)

I'm trying to figure out the best way of doing this....SQL SERVER stored procedure? also contemplating doing it in c#, but either way I'm sortof at a stand still.
Basically what I have is a parts table and a column with qty. This qty column could be a fixed number but it could also be dependent on other parameters. (length, width, size etc...). This was originally a very basic project and I cheated with a few if statements, however an increasing number of parts have a calculated quantity. I want to be able to execute a function stored as a string when a certain part should be selected.
so then based on the parts needed, a table would be created with part and its corresponding numeric quantity.
I was reading into sp_executesql, EXEC, but they still aren't making sense (havent found an comparable example)
Table:
PART QTY
==========
X 'CASE WHEN #FinWidth >=124 THEN ROUND(1.5 + (#FinHeight-#FinWidth)/2.2,0) ELSE 10 END'
Y '2'
Query:
DECLARE #sqlCommand nvarchar(1000)
DECLARE #qty decimal(18,3)
DECLARE #finHeight decimal(18,3)
DECLARE #finWidth decimal(18,3)
DECLARE #part varchar(80)
SET #finHeight = 120
SET #finWidth = 100
sp_executesql....something??
EXEC(something)??
Something like this can get you to use string from table and calculate it. Since it's dynamic SQL you can't use it as function, so I am not sure how useful it can be... you can maybe try with stored procedure:
DECLARE #sqlCommand nvarchar(MAX)
DECLARE #finHeight decimal(18,3)
DECLARE #finWidth decimal(18,3)
DECLARE #part varchar(80)
SET #part = 'X'
SET #finHeight = 124
SET #finWidth = 400
SELECT #sqlCommand= 'SELECT ' + QTY FROM dbo.Table1 WHERE PART = #part
SET #sqlCommand = REPLACE(#sqlCommand, '#finHeight', #finHeight)
SET #sqlCommand = REPLACE(#sqlCommand, '#finWidth', #finWidth)
EXEC (#sqlCommand)
SQLFiddle DEMO
I would create a function to return quantity based on the business logic related to misc fields. Example function would be
create dbo.fn_GetQuantity(#Qty int, #width decimal(18, 3), #Height decimal(18,3))
returns int
as
begin
-- TODO Apply all business logic related to #width & #height here and calculate new #Qty
return #Qty
end
then in the proc I would just call this new function with needed parameters.
create proc dbo.sGetParts()
as
begin
select Part, dbo.fn_GetQuantity(Qty, finWidth, finWidth)
from parts
end

Multi Language insertion in SQL Server using a stored procedure

I need to insert Tamil language into SQL Server 2005. I have tried using Insert or Update query, it worked fine. While going to stored procedure, I don't know how to pass the parameter.
ALTER PROCEDURE [dbo].[spr_Sam]
#Row_Id int = NULL,
#Description_Ta nvarchar(MAX) = null
AS
BEGIN
update tblTest set
Description_Ta = #Description_Ta
where Row_Id = #Row_Id
END
exec [dbo].[spr_Sam] 2, 'பெண்டிரேம்';
If I execute this it gets inserted as ?????.
exec [dbo].[spr_Sam] 2, N'பெண்டிரேம்';
If I execute this it gets inserted correctly.. but I don't know how to pass that 'N' from my C# Application. I used a text-box to get that Description_Ta parameter.
C# should add the N automatically if you use SqlDbType.NVarChar for SQLParameter
You must be using SqlDbType.VarChar of course
The MSDN doc for SqlDbType states (my bold)
VarChar: A variable-length stream of non-Unicode characters...
...
NVarChar: A variable-length stream of Unicode characters...
Here is the correct update statement:
update tblTest
set Description_Ta = #Description_Ta
where Row_Id = #Row_Id;
You don't need single quotes around a variable.
But, I think the posting is confused. To call the procedure use:
exec [dbo].[spr_Sam] 2, N'பெண்டிரேம்';
To modify it:
ALTER PROCEDURE [dbo].[spr_Sam]
#Row_Id int = NULL,
#Description_Ta nvarchar(MAX) = null
AS
BEGIN
update tblTest
set Description_Ta = #Description_Ta
where Row_Id = #Row_Id;
END;
You shouldn't have arguments when you define the stored procedure.

Row count of a stored procedure from another stored procedure

I have various stored procedures. I need a stored procedure to execute a stored procedure and then return only the row count (number of returned rows by the called procedure) and I need to receive it in c# code.
What's the best way to do this?
Assuming you are using SQL Server (which is possible from the code snippets), perhaps something like this would work for you:
exec('exec <your stored procedure goes here>; select ##RowCount')
Since you are running SQL Server, I can think of one solution that is not necessarily pretty.
Create a temporary table (table variable if you have a more recent version of SQL Server). Then execute:
exec(`
declare #t table (
<columns go here>
);
insert into #t
exec(''<your exec here>'');
select #rowcount
');
And now that I've said that, I would recommend sp_executesql. This goes something like this:
declare #sql nvarchar(max) = N'exec '+#YOURQUERY + '; set #RowCount = ##RowCount';
exec sp_executesql #sql, N'#RowCount int output', #RowCount = RowCount output;
I spent most of yesterday debugging an arcane condition that arises when you call a stored procedure inside an insert.
You can try this in your child stored procedure :
CREATE PROC PawanXX
(
#a INT
,#b INT OUTPUT
)
AS
BEGIN
SELECT TOP 2 * FROM X
SET #b = ##ROWCOUNT
RETURN #b
END
GO
The main stored procedure where we call all other sps
DECLARE #RC int
DECLARE #a int
DECLARE #b int
EXECUTE #RC = [dbo].[PawanXX]
#a
,#b OUTPUT
SELECT #RC
The output for the same
ProcessName Parent Child
ShareDrafts Job12 Job03
ShareDrafts Job13 Job58
(2 row(s) affected)
2
(1 row(s) affected)

Sending an array of values to Oracle procedure to use in WHERE IN clause

I have a stored procedure in Oracle as shown below:
CREATE PROCEDURE MY_TEST_PROC(
CUR OUT SYS_REFCURSOR,
PARAM_THAT_WILL_BE _USED_INSIDE_WHERE_IN
)
AS
BEGIN
OPEN CUR FOR
SELECT *
FROM MY_TABLE
WHERE COL1 IN (here I want to put values received from C#)
END;
On the ASP.NET application side I have a select element with several options. I want to use these list items in my WHERE clause. I know that I can have a VARCHAR2 input parameter in my stored proc, make a comma separated string from the list items, send it to the procedure. There are two concerns with going this way:
I make my website vulnerable to SQL injections
In my stored proc I have to use EXECUTE ('SELECT ...') pattern which I would like to avoid.
How can I send these list items to the stored procedure and use them inside the WHERE IN clause? I'm using ODP.NET and have heard of UDT but don't know how to use it.
One way could be to use a VARRAY for the PARAM_THAT_WILL_BE _USED_INSIDE_WHERE_IN
parameter and use it as described here
I'm not sure, though, how to call it from c#.
Another way is to use varchar2 with a csv as you stated in your question but without dynamic sql, like this:
CREATE PROCEDURE MY_TEST_PROC(
CUR OUT SYS_REFCURSOR,
PARAM_THAT_WILL_BE varchar2)
AS
BEGIN
OPEN CUR FOR
SELECT *
FROM MY_TABLE
WHERE COL1 IN (
select regexp_substr(PARAM_THAT_WILL_BE, '[^,]+',1,level) p
from dual t
connect by level <= regexp_count(PARAM_THAT_WILL_BE, ',') + 1
)
END;
You can add this comma separated input parameter as a varchar() and use following where statement:
where (','||PARAM_THAT_WILL_BE||',' like '%,'||COL1||',%')
for example if PARAM_THAT_WILL_BE='2,3,4,5' and col1=3 we get:
where (',2,3,4,5,' like '%,3,%')
and it's TRUE if COL1 value is in this list.
Here you don't use a dynamic query so you avoid concerns 1) and 2).
For this scenario i used like this
CREATE PROCEDURE MY_TEST_PROC(CUR OUT SYS_REFCURSOR,A in VARCHAR2
)
AS
BEGIN
OPEN CUR FOR
SELECT *
FROM MY_TABLE
WHERE COL1 IN (SELECT REGEXP_SUBSTR(**A**,'[^,]+', 1, LEVEL)
FROM DUAL
CONNECT BY REGEXP_SUBSTR(**A**, '[^,]+', 1, LEVEL) IS NOT NULL)
END;
The A value should contain open and closed qutoes(').
EX: '512,456,4564'
if it one value '512' like this

Linq to sql stored procedure return value

I have the following stored procedure in an SQL Server 2005 database (meant simply to return the database size in MB).
ALTER PROCEDURE [dbo].[dbSize]
AS
BEGIN
SET NOCOUNT ON;
DECLARE #sizeMb int
DECLARE #DB_NAME varchar(100)
SELECT #DB_NAME = DB_NAME()
SELECT #sizeMb = (size*8)/1024 FROM sys.master_files
WHERE DB_NAME(database_id) = #DB_NAME
AND Name = #DB_NAME
RETURN #sizeMb
END
When I run this in SQL Server Management Studio, it works correctly, returning the current DB Size in MB.
I want this to run inside an application, so I added it to a linq to sql datacontext, which generated the following code:
[global::System.Data.Linq.Mapping.FunctionAttribute(Name="dbo.dbSize")]
public int dbSize()
{
IExecuteResult result = this.ExecuteMethodCall(this, ((MethodInfo)(MethodInfo.GetCurrentMethod())));
return ((int)(result.ReturnValue));
}
I call it like so:
int dbSize = db.dbSize();
However, it only returns zero, never anything else. No exceptions of any kind are thrown either.
I experimented with selecting a result and using output parameters, but that didn't help either (the output parameter was zero as well). Any suggestions?
I've run into the same problem. As dumb as it sounds, you have to return a single row with single column containing your value from a stored procedure. L2S doesn't do something akin to ExecuteScalar(...).
If you use a UDF, you'll have better luck. This post speaks to the problem nicely.

Categories