c#: MySQl execute sql file with parameters - c#

With MySqlCommand I'm tryting to execute a .sql that updates my database.
The large file contains updates, deletes, stored procedures and all. It also uses some variables like:
SET #_count := (
SELECT COUNT(*)
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = 'easycertlistfwk_audit'
AND TABLE_NAME = 'AUDIT_TITLE'
AND COLUMN_NAME = 'TI_ORDER');
IF #_count = 0 THEN
ALTER TABLE `AUDIT_TITLE`
ADD COLUMN `TI_ORDER` int(11) NULL AFTER `TI_DESCR`;
The code that I use to execute it withing c# is:
using (MySqlConnection conn = new MySqlConnection(constring))
{
using (MySqlCommand cmd = new MySqlCommand())
{
conn.Open();
cmd.CommandText = File.ReadAllText(dbUpdatesFile);
cmd.ExecuteNonQuery();
conn.Close();
}
}
the cmd.ExecuteNonQuery() method rises an Exception telling me that #_count must be defined. I guess it takes it for one of the parameters that I'm supposed to pass to the command, but in this case, all the code (and hence temporary variable declarations) is within the sql file that I'd like just to execute.
How to do this? Is there a way to ignore params checking and binding?

Related

Verifing if text already exists

I have a sql table that saves a word and I need to check if that word already exists and I so, I should get a message saying that word already exists.
Is it possible? If so how should I do it?
I will leave it down below myccode to add the word for the sql, but if you need something else I will provide you without any problem.
string conn = ConfigurationManager.ConnectionStrings["test"].ConnectionString;
using (SqlConnection sqlConn = new SqlConnection(conn))
{
sqlConn.Open();
string sqlQuery = #"INSERT INTO testetiposdestados(CDU_ESTADOS) VALUES(#estados)";
SqlCommand SQLcm = new SqlCommand();
SQLcm.Connection = sqlConn;
SQLcm.CommandText = sqlQuery;
SQLcm.CommandType = CommandType.Text;
SQLcm.Parameters.AddWithValue("#estados", textBox1.Text);
SQLcm.ExecuteNonQuery();
sqlConn.Close();
}
I'm using c#
You can use IF NOT EXIST statment like so
IF NOT EXISTS (SELECT * FROM testetiposdestados
WHERE CDU_ESTADOS = #estados)
BEGIN
INSERT INTO testetiposdestados(CDU_ESTADOS) VALUES(#estados)
END
Your query will become:
string sqlQuery =
#"IF NOT EXISTS(SELECT *
FROM testetiposdestados
WHERE CDU_ESTADOS = #estados)
BEGIN
INSERT INTO testetiposdestados(CDU_ESTADOS)
VALUES (#estados)
END";
If it inserted successfully it means it was not present in the table already.
I would recommend using a unique constraint:
CREATE UNIQUE CONSTRAINT unq_testetiposdestados_estados
UNIQUE (CDU_ESTADOS);
INSERT INTO testetiposdestados(CDU_ESTADOS)
VALUES(#estados);
This has the advantage that the database ensures that the value is unique, not the application. Hence, this will prevent another INSERT or UPDATE statement from producing a unique value.
Furthermore, this is much safer than the IF approach. That approach is subject to race conditions -- two threads attempting to insert the same value may both succeed.

Quote default values in create table SQL Server command

I want to write a C# method that creates a table and adds a column. The default values for the column is given as argument to the method. What is the safest way to quote the default value in the SQL command?
The code would be something like this:
var defaultValueThatOriginatesFromAnEvilSource = "'; DROP TABLE #Entities; SELECT '"; // the argument
database.RawExecute(string.Format("create table #Entities (somecolumn int default {0})", defaultValueThatOriginatesFromAnEvilSource));
Would a simple replace of the single quotes in the argument take care of all types of injection? Or is there a special method in C# or SQL I should use for this?
One thing to note, is that I create a temp table, and I need that to be accessible to the the next SQL statement (using the same connection).
As what shA.t said you can do this by sqlcommand in C# though it's quite hardwork if you'll be having multiple columns
but here's how to do it using stored procedure in SQL and sqlcommand in C#
in SQL
CREATE PROCEDURE sp_CreateTable
#TableName VARCHAR(50),
#ColumnName VARCHAR(50)
AS
BEGIN
DECLARE #SQLCreate VARCHAR(MAX)
SET #SQLCreate ='CREATE TABLE ' + #TableName
+ '('+#ColumnName+')'
EXEC (#SQLCreate)
END
GO
and in C#
add this using directives
using System.Data;
using System.Data.Client;
SqlConnection con = new SqlConnection("your connection string here");
con.Open();
SqlCommand cmd = new SqlCommand("sp_CreateTable");
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#TableName", SqlDbType.VarChar).Value = "someName";
cmd.Parameters.Add("#ColumnName", SqlDbType.VarChar).Value = "someColumnName";
cmd.ExecuteNonQuery();
con.Close();

SQL Server stored procedure that returns a boolean if table exists, c# implementation

I have created a stored procedure that takes a single argument, the name of a table, and returns 1 if it exists in the database, 0 if it does not. In SQL Server Management Studio testing my stored procedure works exactly as I'd like it to, however I'm having trouble getting that value for use in my C# program.
My options seem to be ExecuteScalar(), ExecuteNonQuery() or ExecuteReader(), none of which seem appropriate for the task, nor can I get them to even retrieve my stored procedure's result.
I have tried assigning my parameter with both cmd.Parameters.AddWithValue and cmd.Parameters.Add again to no avail.
Assuming you have a stored procedure like this which selects either a 0 (table does not exist) or 1 (table does exist)
CREATE PROCEDURE dbo.DoesTableExist (#TableName NVARCHAR(100))
AS
BEGIN
IF EXISTS (SELECT * FROM sys.tables WHERE Name = #TableName)
SELECT 1
ELSE
SELECT 0
END
then you can write this C# code to get the value - use .ExecuteScalar() since you're expecting only a single row, single column:
// set up connection and command
using (SqlConnection conn = new SqlConnection("your-connection-string-here"))
using (SqlCommand cmd = new SqlCommand("dbo.DoesTableExist", conn))
{
// define command to be stored procedure
cmd.CommandType = CommandType.StoredProcedure;
// add parameter
cmd.Parameters.Add("#TableName", SqlDbType.NVarChar, 100).Value = "your-table-name-here";
// open connection, execute command, close connection
conn.Open();
int result = (int)cmd.ExecuteScalar();
conn.Close();
}
Now result will contain either a 0 if the table doesn't exist - or 1, if it does exist.
Use this:
var returnParameter = cmd.Parameters.Add("#ReturnVal", SqlDbType.Int);
returnParameter.Direction = ParameterDirection.ReturnValue;
Your stored procedure should return 0 or 1.

'Invalid object name' for temporary table when using command with parameters

I'm creating a temporary table and populating it with two separate statements using the same command and connection. However, I'm getting an 'Invalid object name' if I create the table with the parameter inserted before the create. If I add it after the create, it works fine.
The temporary table is supposed to last the entire session, so I don't see what it matters when the parameter is added to the command object.
FAILS:
using (SqlConnection conn = new SqlConnection("Data Source=.;Initial Catalog=TEST;Integrated Security=True;"))
using (SqlCommand cmd = conn.CreateCommand())
{
conn.Open();
cmd.Parameters.Add(new SqlParameter("#ID", 1234));
cmd.CommandText = "CREATE TABLE #Test (ID INT NOT NULL PRIMARY KEY, I INT NOT NULL)";
cmd.ExecuteNonQuery();
cmd.CommandText = "INSERT INTO #Test VALUES (#ID, 1)";
cmd.ExecuteNonQuery();
..... more code that uses the table
}
WORKS:
using (SqlConnection conn = new SqlConnection("Data Source=.;Initial Catalog=TEST;Integrated Security=True;"))
using (SqlCommand cmd = conn.CreateCommand())
{
conn.Open();
cmd.CommandText = "CREATE TABLE #Test (ID INT NOT NULL PRIMARY KEY, I INT NOT NULL)";
cmd.ExecuteNonQuery();
cmd.Parameters.Add(new SqlParameter("#ID", 1234));
cmd.CommandText = "INSERT INTO #Test VALUES (#ID, 1)";
cmd.ExecuteNonQuery();
..... more code that uses the table
}
edit:
SQL Profiler shed more light on this.
If the command has any parameters, the underlying code is issuing an "exec sp_executesql". If the Parameters are cleared, the underlying code issues a more direct "CREATE TABLE". Temp tables are cleaned up after an sp_executesql, which explains what I'm seeing here.
To me, this would be a bug in the SqlCommand (or related) code but since I now have an explanation I can move on.
The problem is in fact in "exec sp_executesql" statement. When ADO detects that there are parameters declared in the sqlCommand, uses by default "sp_executesql" instead of "exec". But in this case, the first command is creating a TEMPORAL table and, as known, temporal tables are only valid inside a stored procedure (sp_executesql) and are deleted when exit. So consequently the second INSERT statement is not longer valid in the first example code. In the second one, the temporal table is created sucessfully and the insert statement is executed normally. Hope it helps.
I suspect the state of the first execution fails because it insists that each parameter must be used.

Return value from SQL Server Insert command using c#

Using C# in Visual Studio, I'm inserting a row into a table like this:
INSERT INTO foo (column_name)
VALUES ('bar')
I want to do something like this, but I don't know the correct syntax:
INSERT INTO foo (column_name)
VALUES ('bar')
RETURNING foo_id
This would return the foo_id column from the newly inserted row.
Furthermore, even if I find the correct syntax for this, I have another problem: I have SqlDataReader and SqlDataAdapter at my disposal. As far as I know, the former is for reading data, the second is for manipulating data. When inserting a row with a return statement, I am both manipulating and reading data, so I'm not sure what to use. Maybe there's something entirely different I should use for this?
SCOPE_IDENTITY returns the last identity value inserted into an identity column in the same scope. A scope is a module: a stored procedure, trigger, function, or batch. Therefore, two statements are in the same scope if they are in the same stored procedure, function, or batch.
You can use SqlCommand.ExecuteScalar to execute the insert command and retrieve the new ID in one query.
using (var con = new SqlConnection(ConnectionString)) {
int newID;
var cmd = "INSERT INTO foo (column_name)VALUES (#Value);SELECT CAST(scope_identity() AS int)";
using (var insertCommand = new SqlCommand(cmd, con)) {
insertCommand.Parameters.AddWithValue("#Value", "bar");
con.Open();
newID = (int)insertCommand.ExecuteScalar();
}
}
try this:
INSERT INTO foo (column_name)
OUTPUT INSERTED.column_name,column_name,...
VALUES ('bar')
OUTPUT can return a result set (among other things), see: OUTPUT Clause (Transact-SQL). Also, if you insert multiple values (INSERT SELECT) this method will return one row per inserted row, where other methods will only return info on the last row.
working example:
declare #YourTable table (YourID int identity(1,1), YourCol1 varchar(5))
INSERT INTO #YourTable (YourCol1)
OUTPUT INSERTED.YourID
VALUES ('Bar')
OUTPUT:
YourID
-----------
1
(1 row(s) affected)
I think you can use ##IDENTITY for this, but I think there's some special rules/restrictions around it?
using (var con = new SqlConnection("connection string"))
{
con.Open();
string query = "INSERT INTO table (column) VALUES (#value)";
var command = new SqlCommand(query, con);
command.Parameters.Add("#value", value);
command.ExecuteNonQuery();
command.Parameters.Clear();
command.CommandText = "SELECT ##IDENTITY";
int identity = Convert.ToInt32(command.ExecuteScalar());
}

Categories