When I am running the stored procedure below in SMSS, it works and returns a nice result.
SQL:
EXEC #return_value = [dbo].[xxxxxx_EnergiAllTags]
#SegmentResponseID = 'xxxxxxxxxx'
But when I am trying to run the stored procedure from my C# code, I get an error:
Invalid column name 'Value'
This is my code:
public DataSet GetQuery(string batchNr)
{
SqlConnection conn = new SqlConnection("xxxxxxxx");
SqlCommand command = new SqlCommand("xxxxxx_EnergiAllTags", conn);
SqlDataAdapter da = new SqlDataAdapter(command);
command.CommandType = CommandType.StoredProcedure;
command.Parameters.Add(new SqlParameter("#SegmentResponseID", batchNr));
DataSet ds1 = new DataSet();
command.CommandTimeout = 60000;
try
{
da.Fill(ds1);
return ds1;
}
catch (Exception e)
{
string ex = e.Message;
throw;
}
}
Can anyone that might have a clue help me figure out what the problem is?
****Update as Req*****
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[xxxxxx_EnergiAllTags]
#SegmentResponseID AS VARCHAR(MAX)
AS
BEGIN
SET NOCOUNT ON;
CREATE TABLE #temp (TagName NVARCHAR(MAX),
StartValue NVARCHAR(MAX),
EndValue NVARCHAR(MAX),
Usage NVARCHAR(MAX)
)
INSERT INTO #temp
EXEC [dbo].[xxxxxx_EnergyTagForBatch] #BatchID = #SegmentResponseID,
#TagName = 'T06C02D01E02FQ000.PV'
INSERT INTO #temp
EXEC [dbo].[xxxxxx_EnergyTagForBatch] #BatchID = #SegmentResponseID,
#TagName = 'T06C02D01E02FQ001.PV'
SELECT * From #temp
DROP TABLE #temp
END
Okay i have figured out the problem.
The 2 SP i have both had a temp table called #temp and while i believe they should be localized to each instance, they were not, and mixed, and by that time they gave an error.
Solution, make sure that there are not temp tables with the same name using in the string of stored-procedure you might call.
Related
All I want to do is check if a name exists in a given table in my database or not but I am getting multiple returns from the stored procedure causing an exception.
This is the stored procedure I am using in SQL Server:
CREATE OR ALTER PROCEDURE ContactExists
#Name varchar(50)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #result bit = 0
DECLARE #name varchar(50) = '';
SET #name = (SELECT Name FROM Table)
IF (#name = #Name)
BEGIN
SET #result = 1
RETURN #result
END
RETURN #result
END
GO
And this is the method I am using in C#:
SPstr = "dbo.ContactExists";
SqlCommand cmd = new SqlCommand(SPstr, connection);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#Name", Name);
var returnValue = cmd.Parameters.Add("#result", SqlDbType.Int);
returnValue.Direction = ParameterDirection.ReturnValue;
cmd.ExecuteNonQuery();
return (int)returnValue.Value;
I am getting multiple returns from the stored procedure causing an exception.
I suspect you mean you're getting this:
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
which is going to arise from this:
set #name = (SELECT Name from Table)
if Table has more than one row. Ensure the subquery (SELECT Name from Table) returns at most one row (use a WHERE on the pk, use MAX etc..)
Don't use the return value from stored procedures to return data. It's an old and mostly obsolete way to signal success or failure of the proc. So either use an output parameter:
CREATE OR ALTER PROCEDURE ContactExists
#Name varchar(50), #result bit output
AS
BEGIN
SET NOCOUNT ON;
set #result = 0;
if exists (SELECT * FROM SomeTable where name = #Name)
begin
set #result = 1;
end
END
or a resultset
CREATE OR ALTER PROCEDURE ContactExists
#Name varchar(50)
AS
BEGIN
SET NOCOUNT ON;
declare #result bit = 0;
if exists (SELECT * FROM SomeTable where name = #Name)
begin
set #result = 1;
end
select #result result;
END
I am developing an application for my project using C# windows form. I have a dynamic SQL script, please refer the below script:
I need to give this Dynamic SQL script in C# : (command part)
`command.CommandType = CommandType.Text;
command.CommandText =???`
Please help me out in this. If I give normally I am getting Exception error in #SQL part.
`
Declare #Sql nvarchar(max)
Set #Sql ='CREATE FUNCTION [dbo].geoid (#InStr VARCHAR(MAX))
RETURNS #TempTable TABLE
(id int not null)
AS
BEGIN
SET #InStr = #InStr + '',''
DECLARE #SP INT
DECLARE #VALUE VARCHAR(1000)
WHILE PATINDEX(''%,%'', #INSTR ) <> 0---(1,2,3,4,5,)
BEGIN
SELECT #SP = PATINDEX(''%,%'',#INSTR)
SELECT #VALUE = LEFT(#INSTR , #SP - 1)--=1
SELECT #INSTR = STUFF(#INSTR, 1, #SP, '''')--(2,3,4,5)
INSERT INTO #TempTable(id) VALUES (#VALUE)
END
RETURN
END
'
declare #xyz varchar(200)
Exec (#sql)
`
Why are you creating the function using command text
You can do something like below for dynamic query
public void Test()
{
string commandText = "Select CatId From tbl_T2H_Category Where Category IN (#cat_1,#cat_2 #cat_3)";
SqlCommand command = new SqlCommand(commandText, connection);
command.Parameters.Add("#cat1", SqlDbType.Varchar);
command.Parameters["#cat1"].Value = "category1";
command.Parameters.Add("#cat2", SqlDbType.Varchar);
command.Parameters["#cat2"].Value = "category2";
command.Parameters.Add("#cat3", SqlDbType.Varchar);
command.Parameters["#cat3"].Value = "category3";
}
Have a strange issue, think it's related to the OUT parameters in my stored procedure?
Stored procedure:
ALTER PROCEDURE [dbo].[uspProcessResetRequest]
#user uniqueidentifier,
#company uniqueidentifier,
#mobile nvarchar(50) OUT, -- return phone number
#system nvarchar(256) OUT -- return system name
AS
BEGIN
SET NOCOUNT ON;
SET #mobile = 'error' --for debugging
SET #system = 'error' --for debugging
-- Select matching row from ResetQueue into temporary table
INSERT INTO ResetHistory ([User_ID], MobilePhone, Company_ID, [System], [Status], ResetIP)
SELECT
rq.[User_ID], u.MobilePhone, u.Company_ID, rq.[System], '3', rq.ResetIP
FROM
ResetQueue rq
INNER JOIN
[User] u ON rq.[User_ID] = u.ObjectGuid
WHERE
u.Company_ID = #company
AND rq.[User_ID] = #user
AND rq.[Status] = '2'
SELECT #mobile = u.[MobilePhone]
FROM [user] u
WHERE u.ObjectGuid = #user
SELECT #system = rq.[system]
FROM ResetQueue rq
WHERE rq.[User_ID] = #user
DELETE FROM ResetQueue
WHERE [User_ID] = #user
END
Calling C# code:
try
{
using (SqlConnection conn = new SqlConnection(strConnection))
{
using (SqlCommand cmd = new SqlCommand("dbo.uspProcessResetRequest", conn))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#user", SqlDbType.UniqueIdentifier).Value = strUser;
cmd.Parameters.AddWithValue("#company", SqlDbType.UniqueIdentifier).Value = strCompany;
cmd.Parameters.AddWithValue("#mobile", SqlDbType.NVarChar).Direction = ParameterDirection.Output;
cmd.Parameters.AddWithValue("#system", SqlDbType.NVarChar).Direction = ParameterDirection.Output;
conn.Open();
cmd.ExecuteNonQuery();
conn.Close();
string[] strResult = new string[] { (string)cmd.Parameters["#mobile"].Value, (string)cmd.Parameters["#system"].Value };
return strResult;
}
}
}
catch (Exception err)
{
string strError = err.Message; // Log error
return new string[] { "", "" };
}
The stored procedure runs just fine - all code gets executed but cmd.ExecuteNonQuery(); throws an exception:
SqlException: Error converting data type nvarchar to int.
so I loose the output values.
I'm suspecting that the OUT parameters are facing some issues, but can't seem to crack this nut...
Most other posts I found for this issue relates to Text values being submitted to SqlInt parameters. This seems not the case with this one as the stored procedure actually executes and moves data around as expected.
#Gwashoppa, thx for taking time to answer my question. To my understanding return values are not to be mixed with OUTPUT parameters. But in any case I found the solution - data type and length needs to be set explicitly:
cmd.Parameters["#mobile"].SqlDbType = SqlDbType.NVarChar;
cmd.Parameters["#mobile"].Size = 50;
I thought that happened in the AddWithValue function, but apparently not.
Your C# code looks fine... The fact that the line cmd.ExecuteNonQuery(); throws an exception, signifies that the error must lie with some parameter used by the SP.
You will need to isolate your SP in steps to identify the problem area...
For instance, in this statement does the ResetHistory table have the same column types used in your select?
INSERT INTO ResetHistory ([User_ID], MobilePhone, Company_ID, [System], [Status], ResetIP)
SELECT rq.[User_ID], u.MobilePhone, u.Company_ID, rq.[System], '3', rq.ResetIP
FROM ResetQueue rq
...
In this statement, does the mobilephone column return a Varchar value?
SELECT u.[MobilePhone]
FROM [user] u
WHERE u.ObjectGuid = #user
In this statement, does the system column return a Varchar value?
SELECT rq.[system]
FROM ResetQueue rq
WHERE rq.[User_ID] = #user
I've a table like this
I've another table sections in which there are 6 sections with id from 1 to 6. I get a list of section id from user which gives information about the current active section of user. Suppose the list returned to me has section ids as follows {2,3,4,5} for user with id 1. Now my question is
How can I pass this list of section ids to my stored procedure
I want to update is active flag of record where section id is 1 and user id is 1 since the list of section ids doesn't have an entry of 1
I want to insert a new record of section id 5 for user id 1 in same table as it is returned in list of section ids.
Can anyone please tell me how to achieve this?
I can get total section id's from the following query
select Id from sections
but don't know i will iterate between total list of section id's and compare the list of section ids returned from C#
To answer the complete question.
1. Like I said in the comment: Table valued parameters
First create a UDTT to store your sections ids for input for the stored procedure.
CREATE TYPE [dbo].[SectionIdUDTT] AS TABLE(
[id] int NOT NULL
)
Use this UDTT as a parameter for your stored procedure:
ALTER PROCEDURE [dbo].[YourSPname] #SectionId SectionIdUDTT readonly,
#UserId INT
AS
BEGIN
In order to call this stored procedure you must first fill the SectionIdUDTT before you call the stored procedure.
DECLARE #SectionId AS SectionIdUDTT;
INSERT INTO #SectionId
--your values here
EXEC YourSPname #SectionId, #UserId;
Take a look at DataTable class in order to call this from C#. Make sure the user has execute permissions on the UDTT.
2 in the stored procedure
Set the records to inactive of the user that already existed but are not in the table valued parameter.
UPDATE YourTable
SET IsActive = 0
WHERE UserId = #UserId
AND SectionId NOT IN (SELECT id FROM #SectionId)
AND SectionId IN (SELECT Id FROM sections) --Not really needed
3 in the stored procedure
Just insert the record that not yet exists. I just assume that id is an identity column.
INSERT INTO YourTable (UserId, SectionId, IsActive)
SELECT #UserId,
s.id,
1
FROM #SectionId s
WHERE NOT EXISTS (
SELECT 1
FROM YourTable y
WHERE y.SectionId = s.id
AND y.UserId = #UserId
)
I would recommend Transaction management in your stored procedure.
First I created a method which would call stored procedure, to that method I passed a list of sections(sections table entity) and Customer Id
public bool SaveChatSectionUserMapping(List<Sections> lstSections, int customerId)
{
con = new SqlConnection(connectionString);
bool isUpdated = false;
try
{
string xmlString = string.Empty;
xmlString = XMLOperations.WriteXML(lstSections);
SqlCommand cmd = new SqlCommand("spUpdateSections", con);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#XMLData", SqlDbType.Xml).Value = xmlString;
cmd.Parameters.Add("#CustomerId", SqlDbType.Int).Value = customerId;
SqlParameter param = new SqlParameter();
param.SqlDbType = SqlDbType.Bit;
param.Direction = ParameterDirection.Output;
param.ParameterName = "#Result";
cmd.Parameters.Add(param);
con.Open();
cmd.ExecuteNonQuery();
isUpdated = (param.Value != DBNull.Value) ? Convert.ToBoolean(param.Value) : false;
}
catch (Exception ex)
{
throw ex;
}
finally
{
if (con.State == ConnectionState.Open)
con.Close();
}
return isUpdated;
}
The value of xmlString I get from this line xmlString = XMLOperations.WriteXML(lstSections); is like this
<ArrayOfSection xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Sections>
<UserId>1</UserId>
<SectionId>1</SectionId>
<IsActive>true</IsActive>
</Sections>
<Sections>
<UserId>1</UserId>
<SectionId>2</SectionId>
<IsActive>true</IsActive>
</Sections>
<Sections>
<UserId>1</UserId>
<SectionId>5</SectionId>
<IsActive>true</IsActive>
</Sections>
</ArrayOfSection>
Now in stored Procedure
CREATE Procedure [dbo].[spUpdateSections]
(
#XMLData as XML,
#CustomerId INT,
#Result int Output
)
AS
BEGIN
SET NOCOUNT ON;
Declare #ErrorCode Varchar(100) = '',#propertyCount VArchar(100) = '',#currentCount int=1,#SectionId int, #IsActive bit
Begin TRY
UPDATE Sections
SET
IsActive = 0
WHERE
UserId = #CustomerId
SELECT #propertyCount = convert(VARCHAR, #XMLData.query ('count(/ArrayOfSection/Sections)'))
SET #currentCount = 1
while (#currentCount<=#propertyCount)
Begin
SET #SectionId = #XMLData.value('data(/ArrayOfSection/Sections[sql:variable("#currentCount")]/SectionId)[1]', 'INT')
SET #IsActive = #XMLData.value('data(/ArrayOfSection/Sections[sql:variable("#currentCount")]/IsActive)[1]', 'BIT')
If Exists (SELECT *
FROM
Sections
WHERE
UserId = #CustomerId
AND SectionId = #SectionId)
BEGIN
IF(#IsActive=1)
BEGIN
UPDATE Sections
SET
IsActive = 1
WHERE
UserId = #CustomerId AND
SectionId = #SectionId
END
END
ELSE
BEGIN
IF(#IsActive=1)
BEGIN
INSERT INTO Sections
([SectionId]
,[UserId]
,[IsActive])
VALUES
(#SectionId,#CustomerId,1)
END
END
SET #currentCount = #currentCount + 1
End
SET #Result = 1
ErrorCode:
If(#ErrorCode !='')
BEGIN
--SELECT #BSErrorResult = doctor.GetErrorCodeDetail(#ErrorCode)
SET #Result = 2
END
END TRY
BEGIN CATCH
--Declaring Variable for formating error
Declare #ErrorMessage VARCHAR(max),
#ErrorSeverity INT,
#ErrorState INT
--SELECTING TECHNICAL ERROR
SELECT #ErrorMessage = error_message()
, #ErrorSeverity = error_severity()
, #ErrorState = error_state()
, #ErrorMessage = #ErrorMessage + ' ' + db_name() + ' ' + ' ' + object_name(##PROCID);
RAISERROR (
#ErrorMessage, -- Message text.
#ErrorSeverity, -- Severity.
#ErrorState -- State.
);
End CATCH
END
Another way to Generate XMl would be by using XElement like this
XElement xml = new XElement("Sections",
from col in lstSections
select new XElement("rows",
new XElement("UserId", col.UserId),
new XElement("SectionId", col.SectionId),
new XElement("IsActive", col.IsActive)));
string xmlString = xml.ToString();
I saw few solutions here but none worked. I tried SCOPE_IDENTITY() didn't wotk. the id is autoincrement.
This is my stored procedure
CREATE PROCEDURE [dbo].[uploadVid]
#video varbinary(MAx),
#vidTitle varchar(50),
#vidCategory varchar(50),
#vidDate date,
#vidDescription varchar(Max),
#vidName varchar(50),
#vidSize bigint
AS
INSERT INTO Video(video, vidTitle, vidCategory, vidDate, vidDescription, vidName, vidSize)
VALUES (#video, #vidTitle, #vidCategory, #vidDate, #vidDescription, #vidName, #vidSize)
& in the back end I tried
Object i = register.ExecuteScalar();
&
int newId = (Int32)register.ExecuteScalar();
I put a break point and it gave me a value of null or 0. any help appreciated
Thanks
try this
CREATE PROCEDURE [dbo].[uploadVid]
#video varbinary(MAx),
#vidTitle varchar(50),
#vidCategory varchar(50),
#vidDate date,
#vidDescription varchar(Max),
#vidName varchar(50),
#vidSize bigint
AS
begin
declare #id as int --assuming your identity column is int
INSERT INTO Video(video, vidTitle, vidCategory, vidDate, vidDescription, vidName, vidSize)
VALUES (#video, #vidTitle, #vidCategory, #vidDate, #vidDescription, #vidName, #vidSize)
set #id = scope_identity()
select #id --return the value for executescaler to catch it
end
Probably you don't execute the commands in the correct sequence: (supposing you are using an SQL Server DB)
SqlCommand cmd = new SqlCommand("uploadVid", connnection);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add(.....)
......
// After adding the parameters you execute the command to insert the new row....
int rowsInserted = cmd.ExecuteNonQuery();
if(rowsInserted > 0)
{
SqlCommand cmd1 = new SqlCommand("SELECT SCOPE_IDENTITY()", connection);
int newID = (int)cmd1.ExecuteScalar();
}
ExecuteScalar returns only the value of the first row in the first column of the query executed. In case of an insert this value is meaningless. You need an ExecuteNonQuery that returns the rows inserted by the command. After that run a new command with the SELECT SCOPE_IDENTITY() command text with the ExecuteScalar. This, of course, if you cannot modify the SP, the answer from th1rdey3 is better if you could change the proc because it avoids a run-trip to the database.