Understanding of nested SQL in C# - c#

using (var connection = new SqlConnection(...))
{
string sql = "SELECT * FROM tableA";
using (var command = new SqlCommand(sql,connection))
{
using (var reader = command.ExecuteReader(...))
{
//***************Sample Start
string sql2 = "INSERT into tableB(column1) VALUES('"+reader["column1"]+"')";
using (var command2 = new SqlCommand(sql2,connection))
{
...
}
//***************Sample End
}
}
}
By using the above code snippet, I believe its the best practice to deal with SQL in C#. Now after I retrieve a list of records from tableA, for each of the row I would like to insert into tableB.
However, it's throwing an exception
There is already an open DataReader associated with this Command which must be closed first
I know this problem can be solved by creating another method and insert into the table from there, I'm wondering if there is any other way. Thanks for any input.

You need to use a different sql connection for the insert than for the select...
...but we can do even better. You can re-write this to be one sql statement, like so:
INSERT into tableB(column1)
SELECT column1 FROM tableA
And then run it all at once like this:
string sql = "INSERT into tableB(column1, column2) SELECT column1, #othervalue As column2 FROM tableA;";
using (var connection = new SqlConnection(...))
using (var command = new SqlCommand(sql,connection))
{
command.Paramters.Add("#othervalue", SqlDbType.NVarChar, 50).Value = "something";
connection.Open();
command.ExecuteNonQuery();
}
The single sql statement is typically much faster, and you end up with less code, too. I understand that this is likely a simplified example of your real query, but I promise you: you can re-write it all as one statement.
Additionally, sometimes you still want to do some client-side processing or display with the new records after the insert or update. In that case, you still only need to send one call to the database, but there will be two separate sql statements in that single call. The final code would look more like this:
string sql = "INSERT into tableB(column1, column2) SELECT column1, #othervalue As column2 FROM tableA;"
sql += "SELECT columnn1, #othervalue As column2 FROM tableA;";
using (var connection = new SqlConnection(...))
using (var command = new SqlCommand(sql,connection))
{
command.Paramters.Add("#othervalue", SqlDbType.NVarChar, 50).Value = "something";
connection.Open();
using (var reader = command.ExecuteReader() )
{
while (reader.Read() )
{
//...
}
}
}
And because someone else brought up MARS (multiple active result sets), I'll add that while this can work, I've had mixed results using it for inserts/updates. It seems to work best when everything that shares a connection is only doing reads.

As has been mentioned in comments, you need a separate database connection for the insert. Each connection can handle one active statement at a time, and you have two here - one for the SELECT, one (at a time) for the INSERT.
Try this for instance:
string srcqry = "SELECT * FROM tableA";
using (SqlConnection srccon = new SqlConnection(ConnectionString))
using (SqlCommand srccmd = new SqlCommand(srcqry, srccon))
{
srccon.Open();
using (SqlDataReader src = srccmd.ExecuteReader())
{
string insqry = "INSERT INTO tableB(column1) VALUES(#v1)";
// create new connection and command for insert:
using (SqlConnection inscon = new SqlConnection(ConnectionString))
using (SqlCommand inscmd = new SqlCommand(insqry, inscon))
{
inscmd.Parameters.Add("#v1", System.Data.SqlDbType.NVarChar, 80);
inscon.Open();
while (src.Read())
{
inscmd.Parameters["#v1"].Value = src["column1"];
inscmd.ExecuteNonQuery();
}
}
}
}
Using parameters solves the SQL Injection vulnerability. You should always do this rather than building the query string from raw user input, or from data that you're pulling from a database, or... well, always. Write some helper methods to make it easier if you like, just make sure you do it.

aside from a bad example, why not just simplify the query to
insert into TableB (column1) select column1 from TableA

Related

Changing command type from text to stored procedure stops datareader running

I have a C# web forms project built in VS2010 and I would like to move from using hard coded SQL queries to stored procedures to interrogate my SQL Server database so i can use parameters.
The code I am having difficulty with reads in data from the database using an sql data reader, and creates a comma separated string that i use for a list of available values for a textbox using jquery autocomplete.
This works fine when using hard coded sql but when i try and change this to a stored procedure and add parameters the textbox has no values available. When I debug this i can see that the code inside the while (reader.Read()) is not getting run. Meaning the code to create the comma separated string is not being run.
Using hard coded SQL (this works)
string mySQLQuery = "SELECT col1 from table1"
using (SqlConnection myConnection = new SqlConnection(ConfigurationManager.ConnectionStrings["myConnectionString"].ConnectionString))
using (SqlCommand command = new SqlCommand(mySQLQuery, myConnection))
{
myConnection.Open();
using (SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
//code to create comma separated string
}
}
}
Converted to using stored procedure (this doesn't work)
using (SqlConnection myConnection = new SqlConnection(ConfigurationManager.ConnectionStrings["myConnectionString"].ConnectionString))
using (SqlCommand myCommand = new SqlCommand("storedProcedureName", myConnection))
{
myCommand.CommandType = CommandType.StoredProcedure;
myCommand.Parameters.Add("#param1", SqlDbType.VarChar).Value = value1;
myCommand.Parameters.Add("#param2", SqlDbType.VarChar).Value = value2;
myConnection.Open();
using (SqlDataReader reader = myCommand.ExecuteReader())
{
while (reader.Read())
{
//code to create comma separated string
}
}
}
Any help will be greatly appreciated
I thing the name of param should by without # but it is depends of database. I using without "#" to MSSQL and it works
I use # prefix only in sql command.
"Select * from table where name = #name"
Change this:
myCommand.Parameters.Add("#param1", SqlDbType.VarChar).Value = value1;
to this:
myCommand.Parameters.Add("param1", SqlDbType.VarChar).Value = value1;
for param2 is the same
I have managed to sort this out, the issue was to do with the values of parameters being passed to the stored procedure which is included in code that I didnt include.
The values were being passed to the stored procedure but the procedure was not returning any values which is why it appeared like the while(myreader.read()) line was being skipped.
The code now works fine, thanks everyone for your help.

select query does not work with parameters using Parameters.AddWithValue

The following query in C# doesn't work, but I can't see the problem:
string Getquery = "select * from user_tbl where emp_id=#emp_id and birthdate=#birthdate";
cmdR.Parameters.AddWithValue("#emp_id", userValidate.emp_id);
cmdR.Parameters.AddWithValue("#birthdate", userValidate.birthdate);
OdbcCommand cmdR = new OdbcCommand(Getquery, conn);
OdbcDataReader Reader = cmdR.ExecuteReader();
Reader.HasRows returns no result but when I query it to my database I got data.
I'll assume your code is actually not quite as presented, given that it wouldn't currently compile - you're using cmdR before you declare it.
First, you're trying to use named parameters, and according to the documentation of OdbcCommand.Parameters, that isn't supported:
When CommandType is set to Text, the .NET Framework Data Provider for ODBC does not support passing named parameters to an SQL statement or to a stored procedure called by an OdbcCommand. In either of these cases, use the question mark (?) placeholder.
Additionally, I would personally avoid using AddWithValue anyway - I would use something like:
string sql = "select * from user_tbl where emp_id = ? and birthdate = ?";
using (var connection = new OdbcConnection(...))
{
connection.Open();
using (var command = new OdbcCommand(sql, connection))
{
command.Parameters.Add("#emp_id", OdbcType.Int).Value = userValidate.EmployeeId;
command.Parameters.Add("#birthdate", OdbcType.Date).Value = userValidate.BirthDate;
using (var reader = command.ExecuteReader())
{
// Use the reader here
}
}
}
This example uses names following .NET naming conventions, and demonstrates properly disposing of resources... as well as fixing the parameter issue.
I do think it's slightly unfortunate that you have to provide a name for the parameter when adding it to the command even though you can't use it in the query, but such is life.
Use like this:
string Getquery = "select * from user_tbl where emp_id=? and birthdate=?";
cmdR.Parameters.AddWithValue("#emp_id", userValidate.emp_id);
cmdR.Parameters.AddWithValue("#birthdate", userValidate.birthdate);
OdbcCommand cmdR = new OdbcCommand(Getquery, conn);
OdbcDataReader Reader = cmdR.ExecuteReader();
while(Reader.Read())
{
//Do something;
}
I know this thread is old, but I wanted to share my solution for anyone else coming up on this.
I was having issues with the typical method that Jon posted. I have used it before, but for some reason with this new string I had it was not wanting to actually place the parameter correctly and was causing the reader to not work.
I ended up doing something like this instead, since in the end we are just replacing parts of a string.
string sql = "select * from user_tbl where emp_id = "+ var1 +" and birthdate = "+
var2""
OdbcCommand command = new OdbcCommand(sql);
This was easier for me to get to work. Be warned though, I am not sure if it has any specific drawbacks when compare to using the command parameter method.

Select Into Explanation / Temporary Tables

Based on the tutorial on SQL Temporary Tables, it should be OK to create a temp table by using SELECT * INTO #tempTable FROM tableA but it's throwing me SQLException when I trying to SELECT * FROM #tempTable saying that Invalid object name '#tempTable'. May I know what's the proper way of using a temp table in C#?
string sql = "SELECT * INTO ##tempTable FROM (SELECT * FROM tableA)";
using (var command = new SqlCommand(sql, connection))
{
string sqlNew = "SELECT * FROM ##tempTable";
using (var command2 = new SqlCommand(sqlNew, connection))
{
using (var reader = command2.ExecuteReader())
{
while (reader.Read())
{
Console.WriteLine(reader["column1"].ToString());
}
Console.ReadLine();
}
}
}
My Objective is tryint to using the data retrieved from sqlVar and insert them into a tempTable and perform some operation on it. Very much appreciated if there is some sample code on how to fit the code into the above code. Thank You.
But why you need temp table at SQL server side..
1) if you wish to perform operation on C# side just take data in DATASET instead of DATAREADER .. and
DataSet dataset = new DataSet();
using (SqlConnection conn = new SqlConnection(connString))
{
SqlDataAdapter adapter = new SqlDataAdapter();
adapter.SelectCommand = new SqlCommand("select * from tableA", conn);
conn.Open();
adapter.Fill(dataset);
conn.Close();
foreach (DataRow row in dataset.Tables[0]) // Loop over the rows.
{
// perform your operation
}
}
2) if you need to perform operation on SQL side then create a stored procedure at SQL server .. in the stored procedure create #table and use it ..
3) and you do not want to create DATASET then you can take data LIST and perform your operation on C# side
You are not executing the first command at all, so the SELECT INTO isn't executed, so the temporary table is not created, so you get an error about the table not existing.
The code should read:
string sql = "SELECT * INTO ##tempTable FROM (SELECT * FROM tableA)";
using (var command = new SqlCommand(sql, connection))
{
command.ExecuteNonQuery(); // <-- THIS
string sqlNew = "SELECT * FROM ##tempTable";
using (var command2 = new SqlCommand(sqlNew, connection))
{
using (var reader = command2.ExecuteReader())
{
while (reader.Read())
{
Console.WriteLine(reader["column1"].ToString());
}
Console.ReadLine();
}
}
}
1-SELECT * INTO # tempTable FROM tableA (local temp)or
2-SELECT * INTO ## tempTable FROM tableA (global temp)then
Local temp tables are only available to the current connection for the user; and they are automatically deleted when the user disconnects from instances. Local temporary table name is stared with hash ("#") sign.
Global Temp Table
Global Temporary tables name starts with a double hash ("##"). Once this table has been created by a connection, like a permanent table it is then available to any user by any connection. It can only be deleted once all connections have been closed.
Both, Temporary tables are stored inside the Temporary Folder of tempdb. Whenever we create a temporary table, it goes to Temporary folder of tempdb database.
temp table in SQL DB
Change your temp table from #tempTable to ##tempTable.
Using ## means a global temp table that stays around. You'll need to Drop it after you have completed your task.
If Exists(Select * from tempdb..sysobjects Where id = object_id('tempdb.dbo.#tempTable'))
DROP TABLE #tempTable
I think your answer is in the comment:
Temporary tables available during the session that creates them.
If you want to actualy get the data you have to perform a SELECT statement from this temporary table within the same scope.
One more thing:
I don't see you are executing the var command, you are missing this line:
string sql = "SELECT * INTO ##tempTable FROM (SELECT * FROM tableA)";
using (var command = new SqlCommand(sql, connection))
{
command.ExecuteNonQuery();// This line is missing..
string sqlNew = "SELECT * FROM ##tempTable";
using (var command2 = new SqlCommand(sqlNew, connection))
{
using (var reader = command2.ExecuteReader())
{
while (reader.Read())
{
Console.WriteLine(reader["column1"].ToString());
}
Console.ReadLine();
}
}
}
But missing the line isn't the reason why your implementation is wrong..

sqlite database not returning results

Why my query does not return results?
I'm using C#.
It returns column headers but no rows. Is there a problem with my select statement?
here's my code :
conn = new SQLiteConnection("Data Source=local.db;Version=3;New=False;Compress=True;");
DataTable data = new DataTable();
SQLiteDataReader reader;
using (SQLiteTransaction trans = conn.BeginTransaction())
{
using (SQLiteCommand mycommand = new SQLiteCommand(conn))
{
mycommand.CommandText = "SELECT * FROM TAGTABLE WHERE TAG = '"+tag+"' ;";
reader = mycommand.ExecuteReader();
}
trans.Commit();
data.Load(reader);
reader.Close();
reader.Dispose();
trans.Dispose();
}
return data;
The TAGTABLE has following fields:
TID int,
Tag varchar(500),
FilePath varchar(1000)
You don't need the transaction, try the following:
DataTable data = new DataTable();
using (SQLiteConnection conn = new SQLiteConnection("Data Source=local.db;Version=3;New=False;Compress=True;"))
using (SQLiteCommand mycommand = new SQLiteCommand(conn))
{
mycommand.CommandText = "SELECT * FROM TAGTABLE WHERE TAG = #tag;";
mycommand.Parameters.AddWithValue("#tag", tag);
conn.Open();
using (SQLiteDataReader reader = mycommand.ExecuteReader())
{
data.Load(reader);
}
}
return data;
The most likely reason this won't return anything is if the SELECT doesn't yield any results.
Also note that anything implementing the IDisposable interface can be used in conjunction with the using statement, so manual closing / disposal of objects afterwards is not required.
Notice that the SQL has changed to use a parameterized query, this will help reduce the likelihood of SQL injection attacks, and is generally cleaner.
Since you don't show sample data and what should be returend some general pointers only:
The way you build the SQL is wide open to SQL incjection (a serious security issue)
Depending on the value of tag (for example if it contains ') the above SQL Statement would do something you don't expect
Since everything is wrappend in using (a good thing!) the question is, whether there is some exception thrown inside the using block (check with the debugger)
why are you using a transaction ? I can't see any reason which makes that necessary...
Please show some sample data with param value and expected result...

How to Insert Data on ServerA that comes from Select Data on ServerB?

Scenario:
I have a development SERVERA which I need to insert data from my tableA from ServerB TableA.
SERVERA.TableA:serialnumber = empty,partnumber=empty
Ex:
Database connection string1.
Select serialnumber,partnumber from ServerB.TableA where (serialnumber='1')
Then
Database connection string2
Insert into serialnumber,partnumber from SERVERA.TableA
Result:
SERVERA.TableA:serialnumber = 1,partnumber=2
If you're using Sql Server, you can use Linked Servers to provide the facility you need, you'd then be able to execute the following code on ServerB:
INSERT INTO [dbo].[TableA]
(
SerialNumber,
PartNumber
)
SELECT SerialNumber,
PartNumber
FROM [ServerA].[DatabaseNameOnServerA].[dbo].[TableA]
WHERE SerialNumber = '1'
If you can't use linked servers, or want/need to do it in code then that's also fairly simple:
using (var connection = new SqlConnection(connectionStringForServerA)
{
connection.Open();
var query = "SELECT SerialNumber, PartNumber FROM [dbo].[TableA] WHERE SerialNumber = '1'";
using (var adapter = new SqlDataAdapter(query, connection);
{
var data = new DataTable();
adapter.Fill(data);
using (var connectionB = new SqlConnection(connectionStringForServerB)
{
var query = "INSERT INTO [dbo].[TableA] (SerialNumber, PartNumber) VALUES (#Serial, #Part)";
foreach(DataRow recordFromServerA in data.Rows)
{
using(var command = new SqlCommand(query, connectionB)
{
command.Parameters.AddWithValue("#Serial", recordFromServerA["SerialNumber"]);
command.Parameters.AddWithValue("#Part", recordFromServerA["PartNumber"]);
command.ExecuteNonQuery();
}
}
}
}
}
There are more efficient ways to carry out the insertion, but having the code spell out exactly what it's doing as I've done there should make it quite clear to you how it works (It is worth noting that I haven't actually run the code sample I've given, so it may need a bit of tweaking, it's also Sql Server specific).

Categories

Resources