How to create dynamic parameters in SQL Server stored procedure - c#

I have a form that generate inputs dynamically, then I get their values and generate command parameters dynamically.
SqlConnection con = new SqlConnection(cs);
SqlCommand cmd =new SqlCommand("insert_op",con);
cmd.CommandType = CommandType.StoredProcedure;
for (int i = 0; i < Request.Form.Count; i++)
{
if (Request.Form["frm_option" + (i + 1)] != null)
{
cmd.Parameters.AddWithValue("#op" + i, Request.Form["frm_option" + (i + 1)]);
}
}
try
{
using (con)
{
con.Open();
cmd.ExecuteNonQuery();
}
}
catch
{
}
How can I pass these dynamic parameters to SQL Server stored procedure and how should stored procedure be?

First of all, this isn't the right design.
To achieve your goal you need to pass multiple values in SQL statment as follows
SQL
INSERT INTO tbl_options(op_name) VALUES (value1),(value2),...(nthValue)
Code
Your code will be something like this
string command = "INSERT INTO tbl_options(op_name) VALUES";
for (int i = 0; i < Request.Form.Count; i++)
{
if (Request.Form["frm_option" + (i + 1)] != null)
{
command += "(#op" + i + "),";
cmd.Parameters.AddWithValue("#op" + i, Request.Form["frm_option" + (i + 1)]);
}
}

If you want to "insert each parameter into separate row" then perhaps it is better to use table variable as a stored prosedure parameter?
Your User Defined Table Type and stored procedure might look like:
create type dbo.ValueTableType as table (Value varchar(255))
GO
create procedure dbo.InsertValues
#Values dbo.ValueTableType readonly
as
begin
insert into dbo.YourTable (Value)
select Value from #Values;
end
See this ADO.NET example of how to initialize and pass a table parameter to stored procedure https://stackoverflow.com/a/10409710/623190

You can provide defaults for every field in the table, so any parameters you do not pass in will get the default. Here I demonstrate defaults of NULL.
CREATE PROCEDURE [dbo].[sproc_tbl_options_Insert]
#op_name nvarchar(50) = NULL,
#op_somethingelse nvarchar(5) = NULL,
#op_number int = NULL
AS
BEGIN
INSERT INTO [tbl_options] (op_name, op_somethingelse, op_number)
VALUES (#op_name, #op_somethingelse, #op_number);
END

Related

Error CODE : procedure has too many arguments specified

I have a this SQL Server stored procedure. When I execute it, I'm getting this error:
SQL Server procedure has too many arguments specified
How can I solve this problem? Code is shown below.
When my stored procedure is working, I need to do if record exist update then add record.
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[Insert_MS]
(#SID char(20),
#CREATE_DATETIME char(14),
#MODIFY_DATETIME char(14),
#CREATOR_SID char(20),
#MODIFIER_SID char(20),
#MARK_DELETED char(1),
#TARGET_SID nvarchar(20),
#TARGET_CODE nvarchar(50),
#UNIT nvarchar(100),
#SPECIFICATION nvarchar(1000),
#MATERIALS_SUBCAT nvarchar(1000),
#SORT int,
#SET_UNIT nvarchar(1000),
#ENABLED char(1),
#MARKET_TYPE nvarchar(2)
)
AS
BEGIN
IF EXISTS (SELECT *
FROM [dbo].[M_S]
WHERE [MARKET_TYPE] = #MARKET_TYPE
AND [TARGET_CODE] = #TARGET_CODE
AND [TARGET_SID] = #TARGET_SID)
BEGIN
--update existing record
UPDATE [dbo].[M_S]
SET [MATERIALS_SUBCAT] = #MATERIALS_SUBCAT ,
[SPECIFICATION] = #SPECIFICATION,
[UNIT] = #UNIT
WHERE [MARKET_TYPE] = #MARKET_TYPE
AND [TARGET_CODE] = #TARGET_CODE
AND [TARGET_SID] = #TARGET_SID
END
ELSE
BEGIN
--insert new record
INSERT INTO [dbo].[M_S] ([SID], [CREATE_DATETIME], [MODIFY_DATETIME],
[CREATOR_SID], [MODIFIER_SID], [MARK_DELETED],
[TARGET_SID], [TARGET_CODE], [UNIT], [SPECIFICATION],
[MATERIALS_SUBCAT], [SORT], [SET_UNIT],
[ENABLED], [MARKET_TYPE])
VALUES (#SID, #CREATE_DATETIME, #MODIFY_DATETIME,
#CREATOR_SID, #MODIFIER_SID, #MARK_DELETED,
#TARGET_SID, #TARGET_CODE, #UNIT,
#SPECIFICATION,
#MATERIALS_SUBCAT, #SORT, #SET_UNIT,
#ENABLED, #MARKET_TYPE)
END
END
Then my aspx.cs code is here
cnn.Open();
insertSql += " INSERT INTO [dbo].[MATERIALS_SUBCAT] ([SID],[CREATE_DATETIME], [MODIFY_DATETIME],";
insertSql += " [CREATOR_SID], [MODIFIER_SID], [MARK_DELETED],[TARGET_SID], [TARGET_CODE],";
insertSql += " [UNIT], [SPECIFICATION], [MATERIALS_SUBCAT], [SORT],[SET_UNIT], [ENABLED], [MARKET_TYPE])";
insertSql += " VALUES (#SID, #CREATE_DATETIME, #MODIFY_DATETIME, #CREATOR_SID, #MODIFIER_SID, #MARK_DELETED, #TARGET_SID, #TARGET_CODE, #UNIT, #SPECIFICATION,";
insertSql += "#MATERIALS_SUBCAT, #SORT, #SET_UNIT, #ENABLED, #MARKET_TYPE) ";
SqlCommand cmdStoredProcedure = new SqlCommand("Insert_MS", cnn);
cmdStoredProcedure.CommandType = CommandType.StoredProcedure;
for (int k = 0; k <= dt_sheet.Rows.Count - 1; k++)
{
cmdStoredProcedure.Parameters.AddWithValue("#SID", dt_sheet.Rows[k]["SID"].ToString());
cmdStoredProcedure.Parameters.AddWithValue("#CREATE_DATETIME", dt_sheet.Rows[k]["CREATE_DATETIME"].ToString());
cmdStoredProcedure.Parameters.AddWithValue("#MODIFY_DATETIME", dt_sheet.Rows[k]["MODIFY_DATETIME"].ToString());
cmdStoredProcedure.Parameters.AddWithValue("#CREATOR_SID", dt_sheet.Rows[k]["CREATOR_SID"].ToString());
cmdStoredProcedure.Parameters.AddWithValue("#MODIFIER_SID", dt_sheet.Rows[k]["MODIFIER_SID"].ToString());
cmdStoredProcedure.Parameters.AddWithValue("#MARK_DELETED", dt_sheet.Rows[k]["MARK_DELETED"].ToString());
cmdStoredProcedure.Parameters.AddWithValue("#TARGET_SID", dt_sheet.Rows[k]["分類代碼"].ToString());
cmdStoredProcedure.Parameters.AddWithValue("#TARGET_CODE", dt_sheet.Rows[k]["品項代碼"].ToString());
cmdStoredProcedure.Parameters.AddWithValue("#UNIT", dt_sheet.Rows[k]["單位"].ToString());
cmdStoredProcedure.Parameters.AddWithValue("#SPECIFICATION", dt_sheet.Rows[k]["規格"].ToString());
cmdStoredProcedure.Parameters.AddWithValue("#MATERIALS_SUBCAT", dt_sheet.Rows[k]["品項名稱"].ToString());
cmdStoredProcedure.Parameters.AddWithValue("#SORT", dt_sheet.Rows[k]["SORT"].ToString());
cmdStoredProcedure.Parameters.AddWithValue("#SET_UNIT",null);
cmdStoredProcedure.Parameters.AddWithValue("#ENABLED", dt_sheet.Rows[k]["ENABLED"].ToString());
cmdStoredProcedure.Parameters.AddWithValue("#MARKET_TYPE", dt_sheet.Rows[k]["MARKET_TYPE"].ToString());
cmdStoredProcedure.ExecuteNonQuery();
cnn.Close();
}
Seems like you want to execute the stored procedure each time you loop through your sheet. Moving the Command into the loop and use "using" to easy dispose the command each time, like this:
for (int k = 0; k <= dt_sheet.Rows.Count - 1; k++)
{
using (SqlCommand cmdStoreProcedure = new SqlCommand("Insert_MS", cnn))
{
cmdStoreProcedure.CommandType = CommandType.StoredProcedure;
cmdStoreProcedure.Parameters.AddWithValue("#SID", dt_sheet.Rows[k]["SID"].ToString());
cmdStoreProcedure.Parameters.AddWithValue("#CREATE_DATETIME", dt_sheet.Rows[k]["CREATE_DATETIME"].ToString());
cmdStoreProcedure.Parameters.AddWithValue("#MODIFY_DATETIME", dt_sheet.Rows[k]["MODIFY_DATETIME"].ToString());
cmdStoreProcedure.Parameters.AddWithValue("#CREATOR_SID", dt_sheet.Rows[k]["CREATOR_SID"].ToString());
cmdStoreProcedure.Parameters.AddWithValue("#MODIFIER_SID", dt_sheet.Rows[k]["MODIFIER_SID"].ToString());
cmdStoreProcedure.Parameters.AddWithValue("#MARK_DELETED", dt_sheet.Rows[k]["MARK_DELETED"].ToString());
cmdStoreProcedure.Parameters.AddWithValue("#TARGET_SID", dt_sheet.Rows[k]["分類代碼"].ToString());
cmdStoreProcedure.Parameters.AddWithValue("#TARGET_CODE", dt_sheet.Rows[k]["品項代碼"].ToString());
cmdStoreProcedure.Parameters.AddWithValue("#UNIT", dt_sheet.Rows[k]["單位"].ToString());
cmdStoreProcedure.Parameters.AddWithValue("#SPECIFICATION", dt_sheet.Rows[k]["規格"].ToString());
cmdStoreProcedure.Parameters.AddWithValue("#MATERIALS_SUBCAT", dt_sheet.Rows[k]["品項名稱"].ToString());
cmdStoreProcedure.Parameters.AddWithValue("#SORT", dt_sheet.Rows[k]["SORT"].ToString());
cmdStoreProcedure.Parameters.AddWithValue("#SET_UNIT", null);
cmdStoreProcedure.Parameters.AddWithValue("#ENABLED", dt_sheet.Rows[k]["ENABLED"].ToString());
cmdStoreProcedure.Parameters.AddWithValue("#MARKET_TYPE", dt_sheet.Rows[k]["MARKET_TYPE"].ToString());
// connection.Open();
cmdStoreProcedure.ExecuteNonQuery();
}
}
cnn.Close();
Your code tries to access SQL Commmand: Insert_Materials_SubCategory
Whereas the shown procedure is called: Insert_MS

Update a column in the database, from a list

I am trying to update a column in the database, from a list
command = new SqlCommand("update Login_Users set Password=#a where UserName !='" + null + "'", Db);
Db.Open();
for (int i = 0; i < list.Count; i++)
{
list[i] = Encrypt(list[i]);
command.Parameters.AddWithValue("#a",list[i]);
int a = command.ExecuteNonQuery();
}
but I get this error:
variable name already been declared
Your command only has one parameter, but you are attempting to add a new one through each loop (via AddWithValue ... add with value).
Either put the command declaration in the loop (as below), or use one of the other methods to update the value.
Db.Open();
for (int i = 0; i < list.Count; i++)
{
command = new SqlCommand("update Login_Users set Password=#a where UserName !='" + null + "'", Db);
list[i] = Encrypt(list[i]);
command.Parameters.AddWithValue("#a",list[i]);
int a = command.ExecuteNonQuery();
}
In query you have one parameter called #a - check if your list has only one item. If not that's problem. Meybe it will be better to remove for loop and assign all parameters manually.
Why in query you do something like this:
where UserName !='" + null + "'"
I think much more readable is like this:
where UserName !=''
or
where UserName <>''
You have setup your SqlCommand with a SQL statement that includes a parameter #a. With that set, you can call the command multiple times via the ExecuteQuery after setting the parameter #a to different values.
Within your for loop, the statement command.Parameters.AddWithValue() is potentially adding to the command additional parameter, but no two parameters can have the same value so if your loop is executed more than once, you'll get the error you received.
Your SQL statement appears to be setting the password of all records in Login_Users to some encrypted value multiple times based on your list. If I understand correctly, maybe this would do what you want:
var command = new SqlCommand("update Login_Users set Password=#a where UserName !='" + null + "'", Db);
Db.Open();
command.Parameters.Add(new SqlParameter("#a",null));
for (int i = 0; i < list.Count; i++)
{
cmd.Parameters["#a"].Value = Encrypt(list[i]);
int a = command.ExecuteNonQuery();
}
Good luck!

C# Code for generating Unique ID for each row inserted into SQL Server 2008 R2

I have written a unique ID generating function that generates a ID every time a new row is inserted into the database. But sometimes it gives same ID for every row. I can't find out what is the problem exactly happening that time. I give you the code for insert into database and code for ID generate. Please review the code and tell me if there is any logical error or not-
// Daily sales report entry codeing…………………………………………………………………………………………………………………
public string GetSalesTeam(SalesTeam st)
{
try
{
SqlConnection con = SqlConnDAC.CreateConn();
SqlCommand cmd = new SqlCommand("Insert into DSR values(#v1,#v2,#v3,#v4,#v5,#v6,#v7,#v8,#v9,#v10,#v11,#v12,#v13,#v14,#v15,#v16)", con);
IDGen.varr = DSR_IDGen(); //Calling id generate function
cmd.Parameters.AddWithValue("#v1", st.Sl_No);
cmd.Parameters.AddWithValue("#v2", st.User_ID);
cmd.Parameters.AddWithValue("#v3", st.Name);
cmd.Parameters.AddWithValue("#v4", st.Branch);
cmd.Parameters.AddWithValue("#v5", st.Desg);
cmd.Parameters.AddWithValue("#v6", st.Visiting_Date);
cmd.Parameters.AddWithValue("#v7", st.Name_Of_Client);
cmd.Parameters.AddWithValue("#v8", st.Address);
cmd.Parameters.AddWithValue("#v9", st.PhNo);
cmd.Parameters.AddWithValue("#v10",Convert.ToInt32(st.QuoteValue));
cmd.Parameters.AddWithValue("#v11", st.Remarks);
cmd.Parameters.AddWithValue("#v12", st.Source);
cmd.Parameters.AddWithValue("#v13",IDGen.varr);
cmd.Parameters.AddWithValue("#v14", st.Month);
cmd.Parameters.AddWithValue("#v15", st.Year);
cmd.Parameters.AddWithValue("#v16",Convert.ToInt32(st.ClosedValue));
// cmd.Parameters.AddWithValue("#v17", st.TypeOfCall);
con.Open();
cmd.ExecuteNonQuery();
con.Close();
return "Success and DSR No.for_ "+st.Name_Of_Client+" = "+IDGen.varr+"";
}
catch (Exception e)
{
return e.ToString();
}
}
//ID generate function………………………………………………………..
public string DSR_IDGen()
{
int i = 0;
string temp;
string var;
var = ("DSR-" + i.ToString()).Trim();
SqlConnection conID = SqlConnDAC.CreateConn();
SqlCommand cmdd = new SqlCommand("select DSR_No from DSR", conID);
conID.Open();
SqlDataReader dr = cmdd.ExecuteReader();
while (dr.Read())
{
temp = (dr[0].ToString()).Trim();
if (var == temp)
{
i = i + 1;
var = ("DSR-" + i.ToString()).Trim();
continue;
}
}
dr.Close();
conID.Close();
return var;
}
// a static variable that holds the ID............................
public class IDGen
{
public static string varr;
}
One word of advice: don't try to make this any more difficult than it is, and don't try to outsmart SQL Server. Why don't you just use the database-provided mechanisms that's already in place for this: an IDENTITY column?
I would recommend you use:
an ID INT IDENTITY(1,1) column to get SQL Server to handle the automatic increment of your numeric value
a computed, persisted column to convert that numeric value to the value you need
So try this:
CREATE TABLE dbo.DSR
(ID INT IDENTITY(1,1) NOT NULL PRIMARY KEY CLUSTERED,
DsrID AS 'DSR-' + RIGHT('00000000' + CAST(ID AS VARCHAR(8)), 8) PERSISTED,
.... your other columns here....
)
Now, every time you insert a row into DSR without specifying values for ID or DsrID:
INSERT INTO dbo.DSR(Col1, Col2, ..., ColN)
VALUES (Val1, Val2, ....., ValN)
then SQL Server will automatically and safely increase your ID value, and DsrID will contain values like DSR-0000001, DSR-0000002,...... and so on - automatically, safely, reliably, no duplicates.

no update on sql server database. No errors just no results

//the #Question column name needs to change according to the checkbox. For example Checkbox1 - Question1
SqlConnection con = new SqlConnection(...);
String sql = "UPDATE INQUIRY2 set #Question = #str WHERE email = #email AND base = #base;";
SqlCommand cmd = new SqlCommand(sql, con);
con.Open();
//checkbox2 - question 2
//if (CheckBox3.Checked == true)
//{
// str = str + CheckBox3 + 'x';
//}
DataTable theDataTable = null;
// Verify that dt is actually in session before trying to get it
if(Session["dt"] != null)
{
theDataTable = Session["dt"] as DataTable;
}
//Verify that the data table is not null
if(theDataTable != null)
{
email = theDataTable.Rows[0]["email"].ToString();
base1 = theDataTable.Rows[0]["base"].ToString();
}
//checkbox1 - question 1
if (CheckBox9.Checked == true)
{
str = str + CheckBox9.Text + 'x';
strQuestOne = theDataTable.Columns["Question1"].ToString();
}
cmd.Parameters.AddWithValue("#email", email);
cmd.Parameters.AddWithValue("#str", str);
cmd.Parameters.AddWithValue("#Question", strQuestOne);
cmd.Parameters.AddWithValue("#base", base1);
cmd.ExecuteNonQuery();
con.Close();
You are using a parameter for a column name. Database objects (columns names, tables, stored procedures or any other objects) cannot be passed as parameters. Only actual values for columns or variables can be parameters. You need to build your SQL statement dynamically in this case:
String sql ="UPDATE INQUIRY2 set " + strQuestOne + "= #str WHERE email = ...
But now you should be carefull because you code is at risk of SQL injection attack.
Your SQL uses #param type in the string.
If you are looking to execute a stored procedure of some sort to negate most sql injection attacks on a website you might want to consider calling a stored procedure and adding SqlCommand.Parameter to the SqlCommand.Parameters Collection.
Otherwise if you want to just execute the sql you should do
string sql = String.Format("UPDATE TABLE set COLUMN = {0} where OTHERCOLUMN = {1}", varValue, varWhere);

Pre check for data insertion

I want to make a program for value prechecking .a user will give the single input (wbslement no) to UI .I want to insert that record into System . Before inserting into database I want to check It is present in Table or not . if it is present in table then It should not insert record into table if it is not present into database then it should insert .
currently at load time I am fetching all the records from table after that I am trying to insert into System.
in my code it is inserted value any case
CrCon = new SqlConnection(spcallloggin);
CrCon.Open();
CrCmd = new SqlCommand();
CrCmd.Connection = CrCon;
CrCmd.CommandText = "GetOraderNumberDetail";
CrCmd.CommandType = CommandType.StoredProcedure;
sqladpter = new SqlDataAdapter(CrCmd);
ds = new DataSet();
sqladpter.Fill(ds);
for (int count = 0; count < ds.Tables[0].Rows.Count; count++)
{
if (txtwbs.Text == ds.Tables[0].Rows[count][0].ToString())
{
Lbmsg.Visible = true;
Lbmsg.Text = "Data Already Exists !";
count = count + 1;
}
else
{
insetreco(val);
}
}
You could use DataView's RowFilter for querying in-memory tables :
Dataview dv = ds.Tables[0].DefaultView ;
dv.RowFilter="wbslement_no="+number;
if(dv.ToTable().Rows.Count==0)
{
//insert into database
}
else
{
Lbmsg.Visible = true;
Lbmsg.Text = "Data Already Exists !";
}
Or
Instead of two separate calls to the database , you could check for duplicity inside your Stored Procedure.
Just make a "Unique" key constraint on the table itself. MySQL already has an existing construct to handle this, so there's no point doing in your code.
It is better to check it directly in the stored procedure.
IF NOT EXISTS(SELECT * FROM [TABLE] WHERE unique_field = "value of the txtwbs")
BEGIN
INSERT INTO [TABLE]
VALUES (value1, value2, value3,...)
END
Also you can change your code as following:
bool doesExist;
for (int count = 0; count < ds.Tables[0].Rows.Count; count++)
{
if (txtwbs.Text == ds.Tables[0].Rows[count][0].ToString())
{
Lbmsg.Visible = true;
Lbmsg.Text = "Data Already Exists !";
doesExist = true;
break;
}
}
if(!doesExist)
insetreco(val);
Check this :
Make changes according to your need
IF EXISTS (SELECT 1 FROM targetTable AS t
WHERE t.empNo = #yourEmpNo
AND t.project = #yourProject)
BEGIN
--what ever you want to do here
END
ELSE
BEGIN
INSERT INTO yourTable (empno, name, project)
SELECT #empno, #name, #project
END

Categories