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";
}
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
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.
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 have a windows form where the user can input multiple values in multiple textboxes for faster search results. But when running, it takes only 1st parameter i.e., the fullname and ignores the other. Don't know the reason why is it so. Am getting the full table in the result which I don't want. I have created a stored procedure.
CREATE PROCEDURE USP_SELECT_CUSTOMERS (
#fullName VARCHAR(100) = '',
#Address VARCHAR(100) = '',
#ContactNumber VARCHAR(15) = ''
)
AS BEGIN
SELECT * FROM Customers
WHERE ((ContactName LIKE #fullName+'%') OR (#fullName = ''))
OR ((Address LIKE #Address+'%') OR (#Address = ''))
OR ((Phone LIKE #ContactNumber+'%') OR (#ContactNumber = ''))
END
Here's how am i calling the stored procedure in my program :=>
private void btnSubmit_Click(object sender, EventArgs e)
{
try
{
con.Open();
SqlCommand cmd = new SqlCommand("USP_SELECT_CUSTOMERS", con);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#fullName", txtFullName.Text);
cmd.Parameters.AddWithValue("#Address", txtAddress.Text);
cmd.Parameters.AddWithValue("#ContactNumber", txtContactNumber.Text);
SqlDataAdapter da = new SqlDataAdapter(cmd);
DataSet ds = new DataSet();
da.Fill(ds);
if (ds.Tables[0].Rows.Count > 0)
{
dataGridView1.Visible = true;
dataGridView1.DataSource = ds.Tables[0];
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message.ToString());
}
finally
{
con.Close();
}
}
What I want is even if the 1 textbox if filled, the stored procedure should give the desired output. Kindly help me out in this.
Thanks.
You should AND instead of OR. Try this:
CREATE PROCEDURE USP_SELECT_CUSTOMERS (
#fullName VARCHAR(100),
#Address VARCHAR(100),
#ContactNumber VARCHAR(15)
)
AS BEGIN
SELECT * FROM Customers
WHERE ((ContactName LIKE #fullName+'%') OR (#fullName = ''))
AND ((Address LIKE #Address+'%') OR (#Address = ''))
AND ((Phone LIKE #ContactNumber+'%') OR (#ContactNumber = ''))
END
It will give you the desired result.
See SQL Fiddle
EDIT:
As per your requirement, use this query:
CREATE PROCEDURE USP_SELECT_CUSTOMERS
(
#fullName VARCHAR(100),
#Address VARCHAR(100),
#ContactNumber VARCHAR(15)
)
AS
BEGIN
IF LEN(#fullName)=0
SET #fullName='$$$'
IF LEN(#Address)=0
SET #Address='$$$'
IF LEN(#ContactNumber)=0
SET #ContactNumber='$$$'
SELECT * FROM Customers
WHERE ((ContactName LIKE #fullName+'%'))
OR ((Address LIKE #Address+'%'))
OR ((Phone LIKE #ContactNumber+'%'))
END
Added a simple trick. See SQL Fiddle.
Replace $$$ with anything which will not be included in ContactName,Address and Phone fields.
I agree with what #Baljeet said ... it should fetch the desired results.
Make Sure you have done the following
1) Intitilise the the parameter value as '' (blank) if varchar
eg #fullName VARCHAR(100) = ''
and in where condition like given below, people tend to make mistake in the second condtion of OR.
Make sure the condtion is Where ( 'Field Name' like '#parametername' OR #parametername ='')
WHERE ((ContactName LIKE #fullName+'%') OR (#fullName = ''))
As well as carrying out the changes in Raging Bull's answer, try adding ISNULL to your second check for each parameter. So
#fullname = ''
becomes
ISNULL(#fullname, '') = ''
and do the same for the other two parameters.
From memory Sql Server will only use the default value you specify for the parameters, if you don't pass the parameter at all, if you do pass the parameter but the value is null then your query will only work with the change above.
My suggestion would be to define the stored procedure with default value of parameters as NULL. Database is good at handling NULL values and it would keep the stored procedure definition simple.
Then pass the parameters from C# conditionally:
if(!String.IsNullOrEmpty(txtFullName.Text))
cmd.Parameters.AddWithValue("#fullName", txtFullName.Text);
//...add other parameters the same way
Stored procedure should be defined as below:
CREATE PROCEDURE USP_SELECT_CUSTOMERS (
#fullName VARCHAR(100) = NULL,
#Address VARCHAR(100) = NULL,
#ContactNumber VARCHAR(15) = NULL
)
AS BEGIN
SELECT * FROM Customers
WHERE ContactName LIKE #fullName+'%'
OR Address LIKE #Address +'%'
OR Phone LIKE #ContactNumber+'%'
--in case you want to select all rows if all the parameters are NULL then add
--this condition too
--OR 1 = CASE WHEN COALESCE(#fullName, #Address, #ContactNumber,'') = '' THEN 1 ELSE 0 END
END
IMO,
this should do
CREATE PROCEDURE USP_SELECT_CUSTOMERS (
#fullName VARCHAR(100) = '',
#Address VARCHAR(100) = '',
#ContactNumber VARCHAR(15) = ''
)
AS BEGIN
SELECT * FROM Customers
WHERE ((ContactName LIKE #fullName+'%') OR (#fullName = ''))
AND ((Address LIKE #Address+'%') OR (#Address = ''))
AND ((Phone LIKE #ContactNumber+'%') OR (#ContactNumber = ''))
END
using northwind i get following , command with EXEC USP_SELECT_CUSTOMERS 'maria','',''
exec USP_SELECT_CUSTOMERS 'maria','Ã…kergatan 24',''
--result row is displayed now check the next pic
** exec USP_SELECT_CUSTOMERS 'maria','Ã…kergatan 24 ','' **
--because of extra space end of address parameter you could see no result
I have a drop down list on my web page, the selected item of which has to be passed to the Stored Procedure query in the database. However, I am getting a strange error here at adp.Fill(ds) in my bind method.
The exception always says "Incorrect syntax near the keyword 'to'.", where to is always the second word in the drop down option.
For eg: Items in dropdown- 9 to 5 (2nd word: to) , age of empires (2nd word: of)
Exceptions:
Incorrect syntax near the keyword 'to'
Incorrect syntax near the keyword 'of' etc.
Here's the method that I am using:
private void Bind(string ss)
{
SqlDataAdapter adp = new SqlDataAdapter("Retrieve", ConfigurationManager.ConnectionStrings["cn"].ConnectionString);
DataSet ds = new DataSet();
adp.SelectCommand.CommandType = CommandType.StoredProcedure;
adp.SelectCommand.Parameters.Add("#s1", SqlDbType.NVarChar, 255).Value = ss;
adp.SelectCommand.Parameters.Add("#s2", SqlDbType.NVarChar, 255).Value = DropDownList1.SelectedItem.ToString();
adp.Fill(ds);
DataList1.DataSource = ds;
DataList1.DataBind();
}
StoredProcedure
ALTER PROCEDURE [dbo].[Retrieve_SegmentedQ]
(
#s1 nvarchar(255),
#s2 nvarchar(255)
)
AS
BEGIN
DECLARE #query nvarchar(max)
SET #query = 'SELECT DISTINCT Details from tbData WHERE Name IN (' + #s1 + ') AND UnsegmentedQuery=' + #s2
exec sp_executesql #query
END
Any suggestions what's wrong here?
update the procedure like below
ALTER PROCEDURE [dbo].[Retrieve_SegmentedQ]
(
#s1 nvarchar(255),
#s2 nvarchar(255)
)
AS
BEGIN
DECLARE #query nvarchar(max)
SET #query = 'SELECT DISTINCT Details from tbData WHERE Name IN (''' + #s1 + ''') AND UnsegmentedQuery=''' + #s2 + ''''
exec sp_executesql #query
END
The bug is here:
SET #query = 'SELECT DISTINCT Details from tbData WHERE Name IN (' + #s1 + ') AND UnsegmentedQuery=' + #s2
You have stored procedure but using it as query, so making something like sql injection. as result you will have following query:
SET #query = 'SELECT DISTINCT Details from tbData WHERE Name IN (5 to 9) AND UnsegmentedQuery=age of empires
which is wrong.
make it in following way add single quotation marks to your params.
SET #query = 'SELECT DISTINCT Details from tbData WHERE Name IN (''' + #s1 + ''') AND UnsegmentedQuery=''' + #s2 + ''''
Your command text name should be same as your procedure name....and here they both are different