stored procedure returns varchar in LINQ - sql-server

I would like to know if in SQL is it possible to return a varchar value from a stored procedure, most of the examples I have seen the return value is an int
Example within a proc
declare #ErrorMessage varchar(255) if #TestFlag = 0 set #ErrorMessage = 'Test'
return #ErrorMessage
calling on asp.net
Updated:
Error:
Conversion failed when converting the varchar value 'Development' to data type int.
using (DataContextDataContext dc = conn.GetContext())
{
string serverName = ""
var result = dc.spGetServerName(ref serverName);
return result.ToString();
}

No, you can't return anything but an int using the RETURN statement.
You'd need to use OUTPUT parameters instead. They are more flexible.
e.g.
CREATE PROCEDURE dbo.ExampleSproc
#OutParam VARCHAR(10) OUTPUT
AS
SET #OutParam = 'Test'
...
GO
Update:
For an example on how to retrieve the output param, see this article.

No. Please see: http://msdn.microsoft.com/en-us/library/ms174998.aspx

Related

How can I add defined parameter to (NEXT VALUE FOR) command?

CREATE OR ALTER FUNCTION sso.FINDSEQVALUE
(#sequence_text text)
RETURNS int
AS
BEGIN
DECLARE #value int;
DECLARE #sequence_value nvarchar(150);
SELECT #sequence_value = CAST(#sequence_text AS nvarchar(150));
SELECT #value = NEXT VALUE FOR #sequence_value;
RETURN #value;
END;
I have a problem. I have created a function on SQL Server and I defined the parameter as you can see. But I cannot add the this command #sequence_value after NEXT VALUE FOR command and I am getting an error.
Incorrect syntax near '#sequence_value'
Somebody can say that "You can use (SELECT NEXT VALUE FOR [SEQUENCE])". But I need this function because of there are two different database on my project. I need same function for databases. In addition function parameter need to be text.
What should I do?

Is it possible to pass a NULL into an SQL Server Stored Procedure from Typescript

I'm stuck in a situation where i have to pass a value as Null to a uniqueidentifier variable i declared in a stored procedure.
The problem is that i have to pass an empty string to the variable, where it generates an error "Cannot convert varchar to uniqueidentifier". From eecuting the procedure in SQL serve, all works well, but typescript generates the above error...
Here is the procedure code executed:
USE [CMS_ONE]
GO
DECLARE #return_value int
EXEC #return_value = [dbo].[PrAdmissionReports]
#session = '82c16d40-56ba-4e5a-b6f4-8f3767fc48fa',
#campus = '0EF13205-3150-43F3-A37A-CDE57BFD544E',
#program = '929A0FCD-81C8-44D3-AC56-020E7C0AA2B2',
#fromDate = '2018-07-02',
#toDate = '2018-07-27'
SELECT 'Return Value' = #return_value
GO
I'm passing #program as ProgramDetailID = null to the procedure, but it keeps returning the error.
This is how i pass the values from the front:
this.sessionID +
"," +
this.campusID +
"," +
this.programDetailID +
"," +
this.fromDate +
"," +
this.toDate
Any help will be greatly appreciated
For sanity's sake I'm assuming you're using a javascript based backend here and not just calling directly into your database from the frontend because that would be dangerous.
You're concatenating an empty string there. you could use something like:
this.someField ? this.someField : 'NULL'
or
this.someField ?? 'NULL'
a better, safer way would be to parameterize your queries.

Throwing errors - The correct % formatting values in error message

I'm trying to throw a custom error from my stored procedure in SQL Server but am getting an error when compiling. The problem is clear. I am trying to display the value of a parameter of type bit and I believe my format statement is wrong. I have the following:
EXEC sys.sp_addmessage
#msgnum = 60000
,#severity = 16
,#msgText = N'Bad parameter. You cannot pass NULLs to this procedure, UseAlternateEquity (%i), AlternateEquity (%d), PushEmail (%i)'
,#lang = NULL;
declare #msg1 NVARCHAR(2048) = FORMATMESSAGE(60000, #UseAlternateEquity, #AlternateEquity, #PushEmail);
throw 60000, #msg1, 1;
The variables #UseAlternateEquityand #PushEmailare of type bit
Could someone tell me what the appropriate format type is please. I have searched high and low and can't find the answer
Just cast your #UseAlternateEquity and #PushEmail to another type prior to pass them. You can cast them to varchar or to int like this
(I'm on the 2008 so I can RAISERROR)
declare #UseAlternateEquityand bit = 1,
#PushEmailare bit = 0,
#AlternateEquity bit = 1;
declare #UseAlternateEquityand_1 int = #UseAlternateEquityand,
#PushEmailare_1 int = #PushEmailare,
#AlternateEquity_1 int = #AlternateEquity;
RAISERROR ( N'Bad parameter. You cannot pass NULLs to this procedure, UseAlternateEquity (%u), AlternateEquity (%u), PushEmail (%u)',
16,
1,
#UseAlternateEquityand_1,
#AlternateEquity_1,
#PushEmailare_1);

How to use RETURN_VALUE parameter in 'Create proc as EXEC' in Sybase?

I'm trying to prepare stored procedure with TDS_DYN_PREPARE like
'create proc dyn1 as EXEC #RETURN_VALUE = sel_from_emp'
If I trying to use statement as is error 'Must declare variable '#RETURN_VALUE'
If parameter name replaced with ? (required for input params, but I tried on return value too) error
'The untyped variable ? is allowed only in in a WHERE clause or the SET clause of an UPDATE statement or the VALUES list of an INSERT statement'
Is it possible to use return value in such statement and if yes - how?
What you're doing here is executing a proc named sel_from_emp which apparently returns a status value (ASE procs can do that). Is this what ypu expected?
This status value is captured in variable #RETURN_VALUE -- but that variable is not declared, so you must add a statement DECLARE #RETURN_VALUE INT.
Note that capturing the proc return statis mskes sense pmly when you sre going to do domething with that value, otherwise you can you do EXEC sel_from_emp.

Receiving one out of few Result Sets in stored procedure

I have a stored procedure that works fine but it has inside it three "select"s.
The selects are not from an inner temporary table.
This is mainly the format of the procedure:
ALTER PROCEDURE [dbo].[STProce]
#param1 int,
#param2 int,
#param3 int,
#param4 int,
#param5 int
AS
select #param1 as p1, #param2 as p2, #param3 as p3
.
.
.
select #param4 as p4
.
.
.
select #param5 as p5
I'm executing the procedure from another procedure and need to catch it there.
I created a table and inserts into it the "exec" from the procedure, like that:
CREATE TABLE #stalledp
(
RowNumber INT,
fldid INT,
fldLastUpdated datetime,
fldCreationDate datetime,
fldName nvarchar(255),
fldPending nvarchar(255)
)
INSERT INTO #stalledp (RowNumber,fldid,fldLastUpdated,fldCreationDate,fldName,fldPending)
EXEC spDebuggerViews_GetStuckWorkflowInstances #workflowSpaceId='00000000-0000-0000-0000-000000000000',#pageNum=1,#pageSize=100000,#orderByColumn=N'fldid',#sortOrder=1,#workflowInstanceId=0,#stuckInstanceType=1,#createdDateFrom='1900-01-01 00:00:00',#createdDateTo='9999-01-01 23:59:59',#updatedDateFrom='1900-01-01 00:00:00',#updatedDateTo='9999-01-01 23:59:59'
Afterwards I receive this error:
Column name or number of supplied values does not match table definition.
The order and name of columns of the table is exactly like the procedure returns.
Is there a possibility to catch only one of the tables that the procedure returns and avoid the other? I cannot change the procedure at all.
I tried declaring a table the same fields as the first select of the procedure and I get an error says that
Thank you in advance!
If all of the result sets returned are of the same structure, then you can dump them to a temp table as you are trying to do. However, that only gets you so far because if the data in the fields cannot be used to determine which result set a particular row came from, then you just have all of the result sets with no way to filter out the ones you don't want.
The only way to interact with multiple result sets individually, regardless of them having the same or differing structures, is through app code (i.e. a client connection). And if you want to do this within the context of another query, then you need to use SQLCLR.
The C# code below shows a SQLCLR stored procedure that will execute a T-SQL stored procedure that returns 4 result sets. It skips the first 2 result sets and only returns the 3rd result set. This allows the SQLCLR stored procedure to be used in an INSERT...EXEC as desired.
The code for the T-SQL stored proc that is called by the following code is shown below the C# code block. The T-SQL test proc executes sp_who2 and only return a subset of the fields being returned by that proc, showing that you don't need to return the exact same result set that you are reading; it can be manipulated in transit.
C# SQLCLR proc:
using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
public class TheProc
{
[Microsoft.SqlServer.Server.SqlProcedure]
public static void Get3rdResultSetFromGetStuckWorkflowInstances()
{
int _ResultSetsToSkip = 2; // we want the 3rd result set
SqlConnection _Connection = null;
SqlCommand _Command = null;
SqlDataReader _Reader = null;
try
{
_Connection = new SqlConnection("Context Connection = true;");
_Command = _Connection.CreateCommand();
_Command.CommandType = CommandType.StoredProcedure;
_Command.CommandText = "tempdb.dbo.MultiResultSetTest";
// (optional) add parameters (but don't use AddWithValue!)
// The SqlDataRecord will be used to define the result set structure
// and act as a container for each row to be returned
SqlDataRecord _ResultSet = new SqlDataRecord(
new SqlMetaData[]
{
new SqlMetaData("SPID", SqlDbType.Char, 5),
new SqlMetaData("Status", SqlDbType.NVarChar, 30),
new SqlMetaData("Login", SqlDbType.NVarChar, 128),
new SqlMetaData("HostName", SqlDbType.NVarChar, 128),
new SqlMetaData("BlkBy", SqlDbType.VarChar, 5),
new SqlMetaData("DBName", SqlDbType.NVarChar, 128)
});
SqlContext.Pipe.SendResultsStart(_ResultSet); // initialize result set
_Connection.Open();
_Reader = _Command.ExecuteReader();
// Skip a predefined number of result sets
for (int _Index = 0;
_Index < _ResultSetsToSkip && _Reader.NextResult();
_Index++) ;
// Container used to move 1 full row from the result set being read
// to the one being sent, sized to the number of fields being read
Object[] _TempRow = new Object[_Reader.FieldCount];
while (_Reader.Read())
{
_Reader.GetValues(_TempRow); // read all columns
_ResultSet.SetValues(_TempRow); // set all columns
SqlContext.Pipe.SendResultsRow(_ResultSet); // send row
}
}
catch
{
throw;
}
finally
{
if(SqlContext.Pipe.IsSendingResults)
{
SqlContext.Pipe.SendResultsEnd(); // close out result set being sent
}
if(_Reader != null && !_Reader.IsClosed)
{
_Reader.Dispose();
}
_Command.Dispose();
if (_Connection != null && _Connection.State != ConnectionState.Closed)
{
_Connection.Dispose();
}
}
return;
}
}
T-SQL test proc:
USE [tempdb]
SET ANSI_NULLS ON;
IF (OBJECT_ID('dbo.MultiResultSetTest') IS NOT NULL)
BEGIN
DROP PROCEDURE dbo.MultiResultSetTest;
END;
GO
CREATE PROCEDURE dbo.MultiResultSetTest
AS
SET NOCOUNT ON;
SELECT 1 AS [ResultSet], 'asa' AS [test];
SELECT 2 AS [ResultSet], NEWID() AS [SomeGUID], GETDATE() AS [RightNow];
EXEC sp_who2;
SELECT 4 AS [ResultSet], CONVERT(MONEY, 131.12) AS [CashYo];
GO
EXEC tempdb.dbo.MultiResultSetTest;
To do:
Adjust _ResultSetsToSkip as appropriate. If you only want the first result set, simply remove both _ResultSetsToSkip and the for loop.
Define _ResultSet as appropriate
Set _Command.CommandText to be "spDebuggerViews_GetStuckWorkflowInstances"
Create the necessary parameters via SqlParameter (i.e. #workflowSpaceId='00000000-0000-0000-0000-000000000000',#pageNum=1,#pageSize=100000,#orderByColumn=N'fldid',#sortOrder=1,#workflowInstanceId=0,#stuckInstanceType=1,#createdDateFrom='1900-01-01 00:00:00',#createdDateTo='9999-01-01 23:59:59',#updatedDateFrom='1900-01-01 00:00:00',#updatedDateTo='9999-01-01 23:59:59')
If needed, add input parameters to the SQLCLR proc so that they can be used to set the values of certain SqlParameters
Then use as follows:
INSERT INTO #stalledp
(RowNumber,fldid,fldLastUpdated,fldCreationDate,fldName,fldPending)
EXEC Get3rdResultSetFromGetStuckWorkflowInstances;
There is a way to get the first record set but the others, I'm afraid, you're out of luck.
EXEC sp_addlinkedserver #server = 'LOCALSERVER', #srvproduct = '',
#provider = 'SQLOLEDB', #datasrc = ##servername
SELECT * FROM OPENQUERY(LOCALSERVER, 'EXEC testproc2')
EDIT: If you only need to check the other result set for columns to be not null you could predefine the expected results sets like so:
EXEC testproc2 WITH RESULT SETS (
(a VARCHAR(MAX) NOT NULL, b VARCHAR(MAX) NOT NULL),
(a VARCHAR(MAX) NOT NULL)
);
If the query within the stored procedure returns null values a exception is raised at that point in procedure. This will only work on sql server 2012 and upwards though.

Resources