SqlConnection connection = new SqlConnection(connString.ToString());
string select = "SELECT (CASE WHEN MAX(page_no) IS NULL THEN 1 ELSE MAX(page_no)+1 END) FROM dbo.BOOK";
string insert = "INSERT INTO dbo.BOOK (book_id,select) VALUES (121,4)";
SqlCommand sqlCommand = new SqlCommand(insert,connection);
insert.ExecuteNonQuery();
Here I got exception where the insert contains invalid string select.
Please tell me how assign sub query within the insert?
you cannot use a select statement like this
if you want to use a sub query it has to be in single statement
but in above statement you write in different different statement for selection
and insert query .
so cmd.ExecuteNonquery() execute only insert text statement so SQL engine unable to find SELECT(and SELECT is a Reserved keyword) so it gives you a error
if you go with subquery try this
SqlConnection connection = new SqlConnection(connString.ToString());
string select = "SELECT 121, (CASE WHEN MAX(page_no) IS NULL THEN 1 ELSE MAX(page_no)+1 END) FROM dbo.BOOK";
string insert = "INSERT INTO dbo.BOOK (book_id,[select]) "+select;
SqlCommand sqlCommand = new SqlCommand(insert,connection);
sqlCommand.ExecuteNonQuery();
Your query results will return a DataTable. So use a DatAdapter to fill a DataTable.
You are doing it wrong, you have to Execute query on SQLCommand object not on string object try this
using(SqlConnection connection = new SqlConnection(connString.ToString())){
string insert = "Insert Query";
using (SqlCommand sqlCommand = new SqlCommand(insert,connection))
{
con.Open();
int i = sqlCommand.ExecuteNonQuery();
}
}
Update:
var selectQuery = "SELECT (CASE WHEN MAX(page_no) IS NULL THEN 1 ELSE MAX(page_no)+1 END) FROM dbo.BOOK";
var insertQuery = string.format("INSERT INTO dbo.BOOK (book_id,{0}) VALUES (121,4)",selectQuery);
Related
I am inserting a data row into my SQL Server database and then I want to query the data to get the unique identifier from the inserted row but my SqlDataReader is returning an empty dataset. I am thinking it maybe that the transaction hasn't been committed or something like that but I am not sure. I do not get an error.
Here is my code:
try
{
strQuery = "INSERT INTO clientnames VALUES(NEWID(),'" + txtACLastName.Text + "','" + txtACFirstName.Text + "'," + 1 + ")";
using (SqlCommand sqlInsertCmd = new SqlCommand(strQuery, sqlConn))
{
intQueryResult = sqlInsertCmd.ExecuteNonQuery();
if (intQueryResult == 0)
{
blnSuccess = false;
goto InsertClientNamesError;
}
else
{
blnSuccess = true;
}
sqlInsertCmd.Dispose();
}
if (blnSuccess)
{
strQuery = "select clientID from clientnames where firstname = '" + txtACFirstName.Text + "' and lastname = '" + txtACLastName.Text + "'";
using (SqlCommand sqlSelectCmd = new SqlCommand(strQuery, sqlConn))
{
SqlDataReader sqlDataRead = sqlSelectCmd.ExecuteReader();
while (sqlDataRead.Read())
{
strClientID = sqlDataRead.ToString();
}
sqlDataRead.Close();
sqlSelectCmd.Dispose();
}
}
}
catch (Exception exQuery)
{
System.Windows.MessageBox.Show("InsertClientNames: Error, " + exQuery.Message + ", has occurred.");
}
You are not getting the desired result because perhaps the SqlConnection is not opened explicitly (just a guess hard to tell without having full code). But this link shows you how to read from reader --> https://msdn.microsoft.com/en-us/library/haa3afyz(v=vs.110).aspx
But I suggest that you Please do not do it this way. Reason is you are making Two round trips to the DB Server when only one would have done the job for you IF you were using stored procedures. Also you are exposing yourselves to SQL Injection attacks as you are not parameterizing your queries.
Stored procedure:
CREATE PROCEDURE dbo.INS_clientnames
(
#FirstName varchar(100),
#LastName varchar(100),
#NewID int out
)
AS
BEGIN
Declare #Err int
set #NewID = NewID() -- Get the New ID and store it in the variable ( #NewID ) that the SP will return back to the caller
INSERT INTO clientnames values (#NewID , #FirstName , #LastName)
SET #Err = ##ERROR
IF #Error <> 0 -- Check If there was an error
Begin
SET #NewID = -1 -- Indicates that there was an error. You could log this into a Log Table with further details like error id and name.
END
RETURN
END
C# code to execute the above stored procedure and get the NewID:
using(SqlConnection conn = new SqlConnection(connectionString ))
{
using(SqlCommand cmd = new SqlCommand("dbo.INS_clientnames", conn))
{
cmd.CommandType = CommandType.StoredProcedure;
// set up the parameters that the Stored Procedure expects
cmd.Parameters.Add("#FirstName", SqlDbType.VarChar, 100);
cmd.Parameters.Add("#LastName" , SqlDbType.VarChar, 100);
cmd.Parameters.Add("#NewId" , SqlDbType.Int).Direction = ParameterDirection.Output;
// set parameter values that your code will send to the SP as parameter values
cmd.Parameters["#FirstName"].Value = txtACFirstName.Text ;
cmd.Parameters["#LastName"].Value = txtACLastName.Text ;
// open connection and execute stored procedure
conn.Open();
cmd.ExecuteNonQuery();
// read output value from #NewId
int NewID = Convert.ToInt32(cmd.Parameters["#NewId"].Value);
}
}
Add the following line to your stored procedure that inserts the record
SELECT SCOPE_IDENTITY()
This will return the last identity value inserted in that table.
And use cmd.ExecuteScalar() instead of ExecuteNonQuery()
ExecuteScalar() executes the query, and returns the first column of the first row in the result set returned by the query. Additional columns or rows are ignored. [More info][1]
I see two approaches to do this:
either you generate the new GUID on the client side in your C# code and pass it into the query - then you already know what the new id is going to be, so you don't need to do a second query to get it:
you create your GUID on the server side and return it to the caller using the OUTPUT clause in your query
Approach #1:
// define connection string and query
string connStr = "--your connection string here--";
string query = "INSERT INTO dbo.Clients(ClientID, FirstName, LastName) VALUES(#ID, #First, #Last);";
using (SqlConnection conn = new SqlConnection(connStr))
using (SqlCommand cmd = new SqlCommand(query, conn))
{
// create the GUID in C# - this is the ID - no need to go get it again - this *IS* the id
Guid id = Guid.NewGuid();
// set the parameters
cmd.Parameters.Add("#ID", SqlDbType.UniqueIdentifier).Value = id;
cmd.Parameters.Add("#First", SqlDbType.VarChar, 50).Value = "Peter";
cmd.Parameters.Add("#Last", SqlDbType.VarChar, 50).Value = "Miller";
// open connection, execute query, close connection
conn.Open();
cmd.ExecuteNonQuery();
conn.Close();
}
Approach #2:
// define connection string and query
string connStr = "--your connection string here--";
// query has an "OUTPUT" clause to return a newly inserted piece of data
// back to the caller, just as if a SELECT had been issued
string query = "INSERT INTO dbo.Clients(ClientID, FirstName, LastName) OUTPUT Inserted.ClientID VALUES(NEWID(), #First, #Last);";
using (SqlConnection conn = new SqlConnection(connStr))
using (SqlCommand cmd = new SqlCommand(query, conn))
{
// set the parameters - note: you do *NOT* send in a GUID value - the NEWID() will create one automatically, on the server
cmd.Parameters.Add("#First", SqlDbType.VarChar, 50).Value = "Frank";
cmd.Parameters.Add("#Last", SqlDbType.VarChar, 50).Value = "Brown";
// open connection
conn.Open();
// execute query and get back one row, one column - the value in the "OUTPUT" clause
object output = cmd.ExecuteScalar();
Guid newId;
if (Guid.TryParse(output.ToString(), out newId))
{
//
}
conn.Close();
}
Using SQL parameters, I could insert a NULL value to the database using this sort of C# code:
string query = "INSERT INTO table_name (column_name) VALUES (#value)";
using (SqlConnection connection = new SqlConnection(/* connection info */))
{
using (SqlCommand command = new SqlCommand(query, connection))
{
command.Parameters.Add("#value", DBNull.Value);
command.ExecuteNonQuery();
}
}
Not using parameters is usually considered to be bad practice, because of SQL-Injection and some other reasons. But, I am curious to know if there is a way to do so without using them. Something like this:
var nullValue = DBNull.value;
string query = "INSERT INTO table_name (column_name) VALUES (" + nullValue + ")";
or even:
string query = "INSERT INTO table_name (column_name) VALUES (\\NULL\\)";
or whatever. Thanks.
Uhmm yes. You could do that, if you are certain that the column should always be NULL, then you could simply write the SQL statement in a full string, like this.
string query = "INSERT INTO table_name (column_name) VALUES (NULL)";
If you take input from a user, then NEVER do this, this is exactly how you get injected.
var nullValue = DBNull.value;
string query = "INSERT INTO table_name (column_name) VALUES (" + nullValue + ")";
The injection would happen if the nullValue contained something like the string NULL); DROP TABLE table_name. Where the NULL); just completes your own SQL allowing for more SQL code to wreak havoc on your data.
The first rule of web development. NEVER EVER trust user data. Use parameters.
using(SqlConnection connection = new SqlConnection("connection_String"))
{
string query = "INSERT INTO table_name (column_name) VALUES (#val1)";
using(SqlCommand inputQuery = new SqlCommand(query))
{
inputQuery.Connection = openCon;
inputQuery.Parameters.AddWithValue("#val1", DBNull.Value);
try
{
connection.Open();
int recordsAffected = inputQuery.ExecuteNonQuery();
}
catch(SqlException)
{
// error here
}
finally
{
connection.Close();
}
}
}
Please try this..
command.Parameters.AddWithValue(
"#ProductName",
// this requires a cast as ?: must return the same type
String.IsNullOrWhiteSpace(productName)
? (object)DBNull.Value
: (object)productName
);
I'm beginner in SQL and C#. My question is: how do I check whether a row in the table exists or not? Here is my code that I am currently using:
var conn = new SqlConnection(#"Data Source");
conn.Open();
var cmd = new SqlCommand("INSERT INTO Results (PlayerName) VALUES (#PlayerName) " , conn);
cmd.Parameters.Add("#PlayerName",_playerName);
cmd.ExecuteNonQuery();
conn.Close();
I want to check if the player name exists or not, and if not, then add it to the table.
You can check it with Select statement first and then insert it if it is not exist.
Also use using statement to dispose your connection and commands automatically instead of calling Close method manually.
using(var conn = new SqlConnection(yourConnectionString))
using(var cmd = conn.CreateCommand())
{
cmd.CommandText = "Select Count(*) From Results Where PlayerName = #playerName";
cmd.Parameters.Add("#playerName", _playerName);
con.Open();
int count = (int)cmd.ExecuteScalar();
if(count == 0)
{
// It means it does not exist.
cmd.CommandText = "INSERT INTO Results(PlayerName) VALUES (#playerName)";
cmd.ExecuteNonQuery();
}
}
if not exists(select null from Results where PlayerName=#PlayerName) begin INSERT INTO Results (PlayerName) VALUES (#PlayerName) end
I am trying to get the result from a select command:
string strName = dtTable.Rows[i][myName].ToString();
string selectBrand = "SELECT [brand] FROM [myTable] WHERE [myName] = '" + strName + "'";
SqlCommand sqlCmdSelectBrand = new SqlCommand(selectBrand , sqlConn);
sqlCmdSelectBrand .Connection.Open();
sqlCmdSelectBrand .ExecuteNonQuery();
string newBrand = Convert.ToString(sqlCmdSelectBrand .ExecuteScalar());
sqlCmdSelectBrand .Connection.Close();
The select works, I have executed it in SQL Studio, but it does not assign to my variable on the second to last line. Nothing gets assigned to that variable when I debug it...
Any advice?
Your approach to read data returned from a SELECT query is (in this particular context) a bit wrong. Usually you call ExecuteReader of the SqlCommand instance to get back your data.
string strName = dtTable.Rows[i][myName].ToString();
string selectBrand = "SELECT [brand] FROM [myTable] WHERE [myName] = #name";
using(SqlCommand sqlCmdSelectBrand = new SqlCommand(selectBrand , sqlConn))
{
sqlCmdSelectBrand.Parameters.Add(
new SqlParameter("#name", SqlDbType.NVarChar)).Value = strName;
sqlCmdSelectBrand .Connection.Open();
using(SqlDataReader reader = sqlCmdSelectBrand.ExecuteReader())
{
if(reader.HasRows)
{
reader.Read();
string newBrand = reader.GetString(reader.GetOrdinal("Brand"));
..... work with the string newBrand....
}
else
// Message for data not found...
sqlCmdSelectBrand .Connection.Close();
}
}
In your context, the call to ExecuteNonQuery is not required because it doesn't return anything from a SELECT query. The call to ExecuteScalar should work if you have at least one record that match to the WHERE condition
Notice also that you should always use a parameterized query when building an sql command text. Also if you think to have full control of the inputs, concatenating string is the open door to Sql Injection
runtime error 'there is already an open datareader associated with this command which must be closed first'
objCommand = new SqlCommand("SELECT field1, field2 FROM sourcetable", objConn);
objDataReader = objCommand.ExecuteReader();
while (objDataReader.Read())
{
objInsertCommand = new SqlCommand("INSERT INTO tablename (field1, field2) VALUES (3, '" + objDataReader[0] + "')", objConn);
objInsertCommand.ExecuteNonQuery();//Here is the error
}
objDataReader.Close();
I cannot define any stored procedure here.
Any help would we appreciated.
No need to do all that, just turn on MARS and your problem will get solved. In your connection string just add MultipleActiveResultSets=True;
You can't perform an action on that connection while it's still working on reading the contents of a data reader - the error is pretty descriptive.
Your alternatives are:
1) Retrieve all your data first, either with a DataSet or use the reader to populate some other collection, then run them all at once after the initial select is done.
2) Use a different connection for your insert statements.
How about pulling the data into a DataSet via Fill and then iterate through that to perform your insert via NonQuery?
IDbDataAdapter da;
IDbCommand selectCommand = connection.CreateCommand();
selectCommand.CommandType = CommandType.Text;
selectCommand.CommandText = "SELECT field1, field2 FROM sourcetable";
connection.Open();
DataSet selectResults= new DataSet();
da.Fill(selectResults); // get dataset
selectCommand.Dispose();
IDbCommand insertCommand;
foreach(DataRow row in selectResults.Tables[0].Rows)
{
insertCommand = connection.CreateCommand();
insertCommand.CommandType = CommandType.Text;
insertCommand.CommandText = "INSERT INTO tablename (field1, field2) VALUES (3, '" + row["columnName"].ToString() + "'";
}
insertCommand.Dispose();
connection.Close();
Your best bet would be to read the information you need into a list and then iterating the list to perform your inserts like so:
List<String> values = new List<String>();
using(SqlCommand objCommand = new SqlCommand("SELECT field1, field2 FROM sourcetable", objConn)) {
using(SqlDataReader objDataReader = objCommand.ExecuteReader()) {
while(objDataReader.Read()) {
values.Add(objDataReader[0].ToString());
}
}
}
foreach(String value in values) {
using(SqlCommand objInsertCommand = new SqlCommand("INSERT INTO tablename (field1, field2) VALUES (3, '" + value + "')", objConn)) {
objInsertCommand.ExecuteNonQuery();
}
}
INSERT INTO tablename (field1, field2)
SELECT 3, field1 FROM sourcetable
A single SQL statement instead of one per insert. Not sure if this will work for your real-life problem, but for the example you provided, this is a much better query than doing them one at a time.
On a side note, make sure your code uses parameterized queries instead of accepting strings as-is inside the SQL statement - your sample is open to SQL injection.
Several suggestions have been given which work great, along with recommendations for improving the implementation. I hit the MARS limit due to existing code not cleaning up a reader so I wanted to put together a more respectable sample:
const string connectionString = #"server=.\sqlexpress;database=adventureworkslt;integrated security=true";
const bool useMARS = false;
using (var objConn = new System.Data.SqlClient.SqlConnection(connectionString + (useMARS ? ";MultipleActiveResultSets=True" : String.Empty)))
using (var objInsertConn = useMARS ? null : new System.Data.SqlClient.SqlConnection(connectionString))
{
objConn.Open();
if (objInsertConn != null)
{
objInsertConn.Open();
}
using (var testCmd = new System.Data.SqlClient.SqlCommand())
{
testCmd.Connection = objConn;
testCmd.CommandText = #"if not exists(select 1 from information_schema.tables where table_name = 'sourcetable')
begin
create table sourcetable (field1 int, field2 varchar(5))
insert into sourcetable values (1, 'one')
create table tablename (field1 int, field2 varchar(5))
end";
testCmd.ExecuteNonQuery();
}
using (var objCommand = new System.Data.SqlClient.SqlCommand("SELECT field1, field2 FROM sourcetable", objConn))
using (var objDataReader = objCommand.ExecuteReader())
using (var objInsertCommand = new System.Data.SqlClient.SqlCommand("INSERT INTO tablename (field1, field2) VALUES (3, #field2)", objInsertConn ?? objConn))
{
objInsertCommand.Parameters.Add(new System.Data.SqlClient.SqlParameter("field2", String.Empty));
while (objDataReader.Read())
{
objInsertCommand.Parameters[0].Value = objDataReader[0];
objInsertCommand.ExecuteNonQuery();
}
}
}
Option 1:
Must execute query and load data before running another query.
Option 2:
Add MultipleActiveResultSets=true to the provider part of your connection string. See the example below:
<add name="DbContext" connectionString="Data Source=(LocalDb)\v11.0;Initial Catalog=dbName;Persist Security Info=True;User ID=userName;Password=password;MultipleActiveResultSets=True" providerName="System.Data.SqlClient" />
What version of SQL Server are you using? The problem might be with this:
(from http://msdn.microsoft.com/en-us/library/9kcbe65k.aspx)
When you use versions of SQL Server before SQL Server 2005, while the SqlDataReader is being used, the associated SqlConnection is busy serving the SqlDataReader. While in this state, no other operations can be performed on the SqlConnection other than closing it. This is the case until the Close method of the SqlDataReader is called.
So, if this is what's causing your problem, you should first read all the data, then close the SqlDataReader, and only after that execute your inserts.
Something like:
objCommand = new SqlCommand("SELECT field1, field2 FROM sourcetable", objConn);
objDataReader = objCommand.ExecuteReader();
List<object> values = new List<object>();
while (objDataReader.Read())
{
values.Add(objDataReader[0]);
}
objDataReader.Close();
foreach (object value in values)
{
objInsertCommand = new SqlCommand("INSERT INTO tablename (field1, field2) VALUES (3, '" + value + "')", objConn);
objInsertCommand.ExecuteNonQuery();
}
Adding this to connection string should fix the problem.
MultipleActiveResultSets=true
Try something like this:
//Add a second connection based on the first one
SqlConnection objConn2= new SqlConnection(objConn.connectionString))
SqlCommand objInsertCommand= new SqlCommand();
objInsertCommand.CommandType = CommandType.Text;
objInsertCommand.Connection = objConn2;
while (objDataReader.Read())
{
objInsertCommand.CommandText = "INSERT INTO tablename (field1, field2) VALUES (3, '" + objDataReader[0] + "')";
objInsertCommand.ExecuteNonQuery();
}
Best Solution:
There is only problem with your "CommandText" value. Let it be SP or normal Sql Query.
Check 1: The parameter value which you are passing in your Sql Query
is not changing and going same again and again in your ExecuteReader.
Check 2: Sql Query string is wrongly formed.
Check 3: Please create simplest code as follows.
string ID = "C8CA7EE2";
string myQuery = "select * from ContactBase where contactid=" + "'" + ID + "'";
string connectionString = ConfigurationManager.ConnectionStrings["CRM_SQL_CONN_UAT"].ToString();
SqlConnection con = new SqlConnection(connectionString);
con.Open();
SqlCommand cmd = new SqlCommand(myQuery, con);
DataTable dt = new DataTable();
dt.Load(cmd.ExecuteReader());
con.Close();
In order for it to be disposed easily i use the following coding-template :
`using (SqlConnection connection = new SqlConnection("your connection string"))
{
connection.Open();
using (SqlCommand cmd = connection.CreateCommand())
{
cmd.CommandText = "Select * from SomeTable";
using (SqlDataReader reader = cmd.ExecuteReader())
{
if(reader.HasRows)
{
while(reader.Read()){
// assuming that we've a 1-column(Id) table
int id = int.Parse(reader[0].ToString());
}
}
}
}
connection.Close()
}`