Converting Stored Procedure into a query (SQL Server Compact)? - c#

I'm trying to convert the following stored procedure into a query, so that I can use it in SQL Server CE
USE TestResults
GO
CREATE PROCEDURE uspInsertNewTest
(#DeviceSerialNumber nvarchar(50),
#DeviceType nvarchar(50),
#ElapsedTime int)
AS
BEGIN
INSERT INTO [TestResults].[dbo].[Tests]([Date], [Device], [DeviceType], [ExecutionTimeMs])
OUTPUT INSERTED.TestId
VALUES (GETDATE(), #DeviceSerialNumber, #DeviceType, #ElapsedTime)
END
GO
From the above script, all I can understand is that it takes three input parameters
DeviceSerialNumber
DeviceType
ElapsedTime
but it'll update 5 columns in the table Tests including Date and TestId.
Since I can't use stored procedures in SQL Server CE, I've converted the above script into a string query,
string queryString = "INSERT INTO Tests ([Date], [Device], [DeviceType], [ExecutionTimeMs]) VALUES (#Date, #DeviceSerialNumber, #DeviceType, #ElapsedTime)"
Now how to include OUTPUT INSERTED.TestId into the string( queryString ) ?
There's a similar question here, but it doesn't help my problem
Thanks!

You can use ##IDENTITY to return the last inserted identity value:
string queryString = "INSERT INTO Tests " +
"([Date], [Device], [DeviceType], [ExecutionTimeMs]) " +
"VALUES (#Date, #DeviceSerialNumber,#DeviceType, #ElapsedTime); " +
"SELECT ##IDENTITY;"
When you execute your query, you need to set it up to return a single value using the ExecuteScalar method:
var newIdentity;
// set up the queryString variable & command using the above
newIdentity = cmd.ExecuteScalar();
This assumes that the column TestId is an identity column.

Though I accepted Tanner's answer, but I ended up doing like this,
string queryString = "INSERT INTO Tests " + "([Date], [Device], [DeviceType], [ExecutionTimeMs]) " +
"VALUES (#Date, #DeviceSerialNumber,#DeviceType, #ElapsedTime)";
string queryString2 = "SELECT ##IDENTITY";
DbCommand command = factory.CreateCommand ();
command.CommandText = queryString;
// Added Parameters here
command.ExecuteNonQuery ();
command.CommandText = queryString2;
object testId = command.ExecuteScalar ();
So I had to split the query into two string & run ExecuteNonQuery with the first string and run ExecuteScalar with the second string.

Related

How Insert on table IF some value is in database

There is a syntax problem on Asp.Net when I try to run an insert on a table if I have a vlaue in another table that I look for.
I tried different queries and datareaders but that generates a problem, one of the 2 datareaders needs to be closed.
con.Open();
String insertRegInfo = "INSERT INTO Login (NumEmp,Nombre,Apellido,Codigo) values (#NumEmp, #Nombre,#Apellido,#Codigo) SELECT NumEmp from Empleados WHERE NumEmp = " + TxtNumEmp.Text +"" ;
MySqlCommand command = new MySqlCommand(insertRegInfo, con);
LblConfirm.Text = "Confirmado";
command.Parameters.AddWithValue("#NumEmp", TxtNumEmp.Text);
command.Parameters.AddWithValue("#Nombre", TxtNombre.Text);
command.Parameters.AddWithValue("#Apellido", TxtApellido.Text);
command.Parameters.AddWithValue("#Codigo", TxtCodigo.Text);
command.ExecuteNonQuery();
con.Close();
I expect to insert data into the table if any value is true.
Let me start saying that this is a terrible coding practice:
String insertRegInfo = "INSERT INTO Login (NumEmp,Nombre,Apellido,Codigo) values (#NumEmp, #Nombre,#Apellido,#Codigo) SELECT NumEmp from Empleados WHERE NumEmp = " + TxtNumEmp.Text +"" ;
Better is:
String insertRegInfo = "INSERT INTO Login (NumEmp,Nombre,Apellido,Codigo)
SELECT NumEmp,#Nombre,#Apellido,#Codigo from Empleados WHERE NumEmp = #NumEmp" ;
You should use parameters instead and better even Store Procedures.
However, to answer your question. All you need to do is match the number of columns of your SQL Command.
INSERT INTO Login (NumEmp,Nombre,Apellido,Codigo)
SELECT NumEmp, #Nombre,#Apellido,#Codigo from Empleados WHERE…
Note that I removed the values section from the insert. That is not required

Create a MySQL sproc from c#, delimiter issues

I'm trying to create stored procedures from a c# program. It typically reads the sproc definition from a text file, and then run it against the chosen database.
My SQL script file looks like this:
DROP PROCEDURE IF EXISTS MySproc;
DELIMITER //
CREATE PROCEDURE MySproc(
IN Id BIGINT,
IN Reference VARCHAR(255),
IN Bla VARCHAR(255)
)
BEGIN
INSERT INTO TableA(`Id`, `Reference`) VALUES(Id, Reference);
INSERT INTO TableB(`Id`, `Bla`) VALUES(Id, Bla);
END
//
DELIMITER ;
and this works fine in the workbench.
I then execute it with this type of c# code:
using (MySqlCommand sqlCommand = _mySqlConnection.CreateCommand())
{
sqlCommand.Connection = _mySqlConnection;
sqlCommand.CommandText = scriptfile;
sqlCommand.CommandType = CommandType.Text;
sqlCommand.ExecuteNonQuery();
}
And it errors with:
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'DELIMITER //
CREATE PROCEDURE MySproc( IN Id BIGINT
' at line 1
If I remove the DELIMITER // stuff, then it still parses the semi colons between BEGIN and END as a delimiter for the outer statement, and it errors with:
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'END' at line 31
Any idea how I can set either the Command or the something int he script so that it works? Not even sure if the error actually comes from MySQL itself, or from the MySqlCommand library (MySql.Data.6.9.9). And MySQL server is 5.6.25, InnoDB tables.
Can you try replacing the DELIMITER // with something like delimiter $$
Pointless question, sorry, it's embarrassing. This morning, I created a unit test following the top part of this page: https://dev.mysql.com/doc/connector-net/en/connector-net-programming-stored-using.html
and it works fine:
[TestMethod]
public void TestSprocCreationFromMySqlDoc()
{
// from https://dev.mysql.com/doc/connector-net/en/connector-net-programming-stored-using.html
MySqlConnection conn = new MySqlConnection();
conn.ConnectionString = "server=localhost;user=root;database=test;port=3306;password=;";
MySqlCommand cmd = new MySqlCommand();
try
{
Console.WriteLine("Connecting to MySQL...");
conn.Open();
cmd.Connection = conn;
cmd.CommandText = "DROP PROCEDURE IF EXISTS add_emp";
cmd.ExecuteNonQuery();
cmd.CommandText = "DROP TABLE IF EXISTS emp";
cmd.ExecuteNonQuery();
cmd.CommandText = "CREATE TABLE emp (empno INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, first_name VARCHAR(20), last_name VARCHAR(20), birthdate DATE)";
cmd.ExecuteNonQuery();
cmd.CommandText = "CREATE PROCEDURE add_emp(" +
"IN fname VARCHAR(20), IN lname VARCHAR(20), IN bday DATETIME, OUT empno INT)" +
"BEGIN INSERT INTO emp(first_name, last_name, birthdate) " +
"VALUES(fname, lname, DATE(bday)); SET empno = LAST_INSERT_ID(); END";
cmd.ExecuteNonQuery();
}
finally
{
conn.Close();
}
}
Then, I did another test with my own statements (trying to replicate file read from disk, with crlf) and it works too!
cmd.CommandText =
"DROP PROCEDURE IF EXISTS MySproc; " + Environment.NewLine +
"CREATE PROCEDURE MySproc(" + Environment.NewLine +
"IN Id BIGINT," + Environment.NewLine +
"IN Reference VARCHAR(255)," + Environment.NewLine +
"IN Bla VARCHAR(255))" + Environment.NewLine +
"BEGIN " + Environment.NewLine +
"INSERT INTO TableA(`Id`, `Reference`) VALUES(Id, Reference); " + Environment.NewLine +
"INSERT INTO TableB(`Id`, `Bla`) VALUES(Id, Bla); " + Environment.NewLine +
"END";
cmd.ExecuteNonQuery();
And then I ran my original application (that read scripts from files) and it runs ok as well! So I can't explain it. I'm wondering if I did something to the MySql server that affected all connections, or did something in one connection that stayed on, affecting all connections, until a reboot.

C# Alter Table and Add a column programmatically ASP.Net & SQL Server

I have been trying to add a column programmatically in ASP.NET to modify the tables in SQL Server.
Please see the following code:
string suppliernotxt = supplieridlist[1].ToString();
//SqlCommand cmd2 = new SqlCommand("ALTER TABLE [ProductNormalDB] ADD suppliernotxt nvarchar(20) NULL", con);
SqlCommand cmd2 = new SqlCommand("ALTER TABLE ProductNormalDB ADD #supplierlist nvarchar(20) NULL", con);
cmd2.Parameters.AddWithValue("#supplierlist", suppliernotxt);
//cmd2.Parameters.AddWithValue("#supplierlist", suppliernotxt.ToString());
//cmd2.Parameters["#supplierlist"].Value = supplieridlist[x];
cmd2.ExecuteNonQuery();
supplieridlist is an array that acquires all the column names to add into the SQL Server database. For some reason the parametrized method is not working and shows the following error:
Incorrect syntax near '#supplierlist'.
The basic idea is to have a user select from a check box the name of the suppliers, based on the selected number of suppliers the array will create the supplier names for ex. if we selected 3 suppliers, the array will save "Supplier1", "Supplier2", "Supplier3" and then the SqlCommand is supposed to alter the table and add the new columns.
You cannot use parameters to express the name of columns.
Parameters could only be used to express values for WHERE clause or for INSERT or UPDATE statements.
You could use string concatenation for your query text, passing the string value to a stored procedure or use some form of dynamic sql.
Please be very carefull with these kind of approaches because if you don't keep absolute control on the values passed to your code you will be exposed to Sql Injection.
Adding as an example of Dynamic SQL execution, but still vulnerable to SQL Injection
string suppliernotxt = supplieridlist[1].ToString();
string execSQL = "DECLARE #sup nvarchar(15); " +
"SET #sup = '" + suppliernotxt + "'; " +
"EXEC ('ALTER TABLE ProductNormalDB ADD ' + #sup + ' nvarchar(20) NULL')"
SqlCommand cmd2 = new SqlCommand(execSQL, con);
cmd2.ExecuteNonQuery();
As you can see, even with Dynamic SQL there is nothing that prevent an SQL Injection attack passing via the suppliernotxt variable
EDIT As explained in the comments below from #RBarryYoung, a good improvement on the SQL Injection problem for this case of dynamic sql could be the usage of the QUOTENAME function to obtain an Unicode string with the required delimiters around the input string
string execSQL = "DECLARE #sup nvarchar(15); " +
"SET #sup = QUOTENAME('" + suppliernotxt + "'); " +
"EXEC ('ALTER TABLE ProductNormalDB ADD ' + #sup + ' nvarchar(20) NULL')"

How to add bloodgroup in char and symbolic form?

I want to add blood group in my table. It is only storing as "A" meanwhile I want to store data as "A+".
I am using store procedure.
ALTER PROCEDURE [dbo].[spInsertBloodGroup]
#ids as int,
#des as nvarchar(2000),
#abbri as nvarchar(2000),
#Datet as datetime
AS
Begin
insert into tblbloodgroup(intSeqId,varDescription,varAbbrivation,dtCreationDate)
values ( #ids ,#des ,#abbri ,#Datet)
meanwhile my input values are coming from C# file which are written as.
string recordSave = "spInsertBloodGroup'" + seqID+ "','" + Description + "','" + Name + "','" + dateModed + "'";
Consider using an SqlCommand to call your stored procedure, instead of doing manual string concatenation.
var sp = new SqlCommand("spInsertBloodGroup", conn)
{
CommandType = CommandType.StoredProcedure
};
sp.Parameters.Add("#ids", SqlDbType.Int, seqID);
sp.Parameters.Add("#des", SqlDbType.NVarChar, Description);
sp.Parameters.Add("#abbri", SqlDbType.NVarChar, Name);
sp.Parameters.Add("#Datet", SqlDbType.Int, dateModed);
sp.ExecuteNonQuery();
Although, I have to ask why you've created a stored procedure that mimics an insert statement? Why not just create an SqlCommand for the Insert and call it directly? Does the stored procedure do additional things that you aren't showing us?

C# update database

I'm using this string to update database and in this case, it works fine. It updates Znesek_nakupa in in last row:
string sqlUpd = "UPDATE Racun SET Znesek_nakupa='10' WHERE Id_racun= (SELECT MAX(Id_racun) FROM Racun)";
But when I'm trying to insert variable and not just 10 it gives me error:
Error converting data type varchar to numeric.
Code example:
double totalPrice = 1.1;
string sqlUpd = "UPDATE Racun SET Znesek_nakupa='totalPrice' WHERE Id_racun= (SELECT MAX(Id_racun) FROM Racun)";
How can I do this?
This problem less to do with SQL, and more to do with using strings and variables in C#.
In order to insert the value of a variable in a string in C#, you can't just place the name of the variable in the string. The string doesn't "know" that it contains a variable. Here are a couple of approaches that will work instead:
double totalPrice = 1.1;
// string concatenation
string sqlUpd =
"UPDATE Racun SET Znesek_nakupa='" +
totalPrice +
"' WHERE Id_racun= (SELECT MAX(Id_racun) FROM Racun)";
// with string.Format
string sqlUpd = string.Format(
"UPDATE Racun SET Znesek_nakupa='{0}' WHERE Id_racun= (SELECT MAX(Id_racun) FROM Racun)",
totalPrice);
However, the approach of just embedding a variable's value in a SQL query like this is not considered best practice as it risks SQL injection attacks. Usually you would want to use parameterised SQL queries.
A parameterised version of your query would look like this (lifting the example from the page linked to above):
SqlConnection conn = new SqlConnection(_connectionString);
conn.Open();
string s = "UPDATE Racun SET Znesek_nakupa='#totalPrice' WHERE Id_racun= (SELECT MAX(Id_racun) FROM Racun";
SqlCommand cmd = new SqlCommand(s);
cmd.Parameters.Add("#totalPrice", totalPrice);
SqlDataReader reader = cmd.ExecuteReader();
Ok, I got it.
When I try to save variable totalPrice in database it comes to error, because C# has comma as separator. In database I have to send dot instead. So I simple replace comma with dot and now it works perfect.
So code looks like this now:
string sqlUpd = "UPDATE Racun SET Znesek_nakupa='" + Convert.ToString(totalPrice).Replace(',', '.') + "' WHERE Id_racun= (SELECT MAX(Id_racun) FROM Racun)";

Categories

Resources