I am using ADO.NET for querying the SQL Server database. I am trying to get items if present on the table.
My query is executing but returning nothing even if there is.
Here is my code:
public List<string> GetRecords(List<string> itemList)
{
itemList.Add("100");
string list = string.Join(",", itemList.Select(x => string.Format("'{0}'", x)));
string query = #"SELECT Id FROM Employees WHERE Id In (#list)";
using (SqlCommand sqlCommand = new SqlCommand(query,connection))
{
sqlCommand.Parameters.AddWithValue("#list", list);
sqlDataReader = sqlCommand.ExecuteReader();
while (sqlDataReader.Read())
{
employeeList.Add(Convert.ToString(database.Sanitise(sqlDataReader, "Id")));
}
}
}
There are three items in the list the employee with ID=100 is available in the table but the other two's are not. but still the query returning nothing.
SQL profiler showing me this query:
exec sp_executesql N'SELECT
Id
FROM
Employees
WHERE
Id In (#list)',N'#list nvarchar(29)',#list=N'''50'',''23'',''100'''
SQL Server will not interpret your concatenated list as actual code. It remains data always, so it's just one big text string of numbers. That is never going to match a single row.
Instead, use a Table Valued Parameter.
First create a table type in your database, I usually keep a few useful ones around.
CREATE TYPE dbo.IdList (Id int PRIMARY KEY);
Then create a DataTable and pass it as a parameter.
public List<string> GetRecords(List<string> itemList)
{
var table = new DataTable { Columns = {
{ "Id", typeof(int) },
} };
foreach (var id in itemList)
table.Rows.Add(id);
const string query = #"
SELECT e.Id
FROM Employees e
WHERE e.Id IN (SELECT l.Id FROM #list l);
";
using (var connection = new SqlConnection(YourConnString)) // always create and dispose a new connection
using (var sqlCommand = new SqlCommand(query,connection))
{
sqlCommand.Parameters.Add(new SqlParameter("#list", SqlDbType.Structured) {
Value = table,
TypeName = "dbo.IdList",
});
connection.Open();
using (var sqlDataReader = sqlCommand.ExecuteReader())
{
while (sqlDataReader.Read())
{
employeeList.Add((string)sqlDataReader["Id"]);
}
}
}
}
Note also:
using on all SQL objects.
Do not cache a connection object. Create when you need it, dispose with using.
I don't know what your Sanitize function does, but it probably doesn't work. Sanitizing database values correctly is hard, you should always use parameterization.
AddWithValue is a bad idea. Instead specify the parameter types (and lengths/precision) explicitly.
I'm trying to find a way to have access to all the values in a row.
The following code returns one cell. If I change select id to select *, I have access to the row but how can I break it apart?
string find_user = "select id from users where userName = '" + un + "'";
using (SqlConnection con = new SqlConnection(cs))
{
using (SqlCommand cmd = new SqlCommand(find_user, con))
{
con.Open();
user_id = cmd.ExecuteScalar().ToString();
/* use to pass the info to all the pages */
Session.Add("u_id", user_id);
}
}
You cannot access additional columns using .ExecuteScalar(), per the docs:
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.
Although it is not a route that I would recommend, you can iterate through the fields by using an index on a data reader:
SqlDataReader dataReader = cmd.ExecuteReader();
// for the query's result set, this while loop will go through all the records
while (dataReader.Read())
{
// for the current record, this for loop will go through all the fields
for (int i = 0; i < dataReader.FieldCount; i++)
{
var value = dataReader[i]; // do what you need with the data here
}
}
A better approach would be to specify the field names in the SQL query instead of using SELECT *, then get the values from the data reader by the specific field names (not relying on the order of the fields in the DB).
Also, you have a SQL injection vulnerability. You should look up what this means and how to parameterize a query.
I'm using C# and SQL Server. I have a list of IDs for documents which corresponds to the primary key for a table in SQL Server that has a row for each document and the row contains (among other things) the ID and the document for that ID. I want to get the document in the row for each of the IDs. Currently, I execute a query for each ID, but since there are 10,000s of them, this runs a ton of queries and takes a very long time. It ends up being faster to simply load everything from the table into memory and then filter by the ids I have, but that seems inefficient and won't scale over time. If that doesn't make sense, hopefully the following code that takes a long time to run shows what I'm trying to do.
private static Dictionary<Guid, string> foo(IEnumerable<Guid> guids, SqlConnection conn)
{
using (SqlCommand command = new SqlCommand(null, conn))
{
command.CommandText = "select document from Documents where id = #id";
SqlParameter idParam = new SqlParameter("#id", SqlDbType.UniqueIdentifier);
command.Parameters.Add(idParam);
command.Prepare();
var documents = new Dictionary<Guid, string>();
foreach (var guid in guids)
{
idParam.Value = guid;
object obj = command.ExecuteScalar();
if (obj != null)
{
documents[guid] = (string)obj;
}
}
return documents;
}
}
I could programmatically construct query strings to use where clause like this: ".... where id in (ID1, ID2, ID3, ..., ID100)" to get 100 documents at a time or something like that, but this feels janky and it seems to me like there's got to be a better way.
I'm sure I'm not the only one to run into this. Is there an accepted way to go about this?
You can use Table-Valued Parameters with no limits in amount of guids
In the code you will create SqlParameter with all Id's you need to
First you need create type of parameter in the sql server
CREATE TYPE IdTableType AS TABLE
(
Id uniqueidentifier
);
Then in the code
private static Dictionary<Guid, string> foo(IEnumerable<Guid> guids, SqlConnection conn)
{
using (SqlCommand command = new SqlCommand(null, conn))
{
// use parameter as normal table in the query
command.CommandText =
"select document from Documents d inner join #AllIds a ON d.id = a.Id";
// DataTable is used for Table-Valued parameter as value
DataTable allIds = new DataTable();
allIds.Columns.Add("Id"); // Name of column need to be same as in created Type
foreach(var id in guids)
allids.Rows.Add(id);
SqlParameter idParam = new SqlParameter
{
ParameterName = "#AllIds",
SqlDbType=SqlDbType.Structured // Important for table-valued parameters
TypeName = "IdTableType", // Important! Name of the type must be provided
Value = allIds
};
command.Parameters.Add(idParam);
var documents = new Dictionary<Guid, string>();
using (var reader = command.ExecuteReader())
{
while (reader.Read())
{
documents[guid] = reader[0].ToString();
}
}
return documents;
}
}
You don't need to prepare the command any more. Besides after first execution next queries will use same compiled query plan, because query text remain same.
You can bunch them into sets of ids and pass a table valued parameter into the query. With Dapper this looks a bit like:
connection.Query("select document from Documents where id in #ids", new { ids = guids});
BEWARE though theres an 8000 parameter limit in sql so you will need to batch up your reads.
btw.. I'd highly recommend looking at Dapper or another micro orm for this type of data access.
I've heard of parametized sql queries a long time ago but I never really gave any attention to it as I'm used to writing full sql statements. I know it improves security against sql injection so now might be a very good time to adapt change even if it's too late. I got this one from this site http://www.codinghorror.com/blog/2005/04/give-me-parameterized-sql-or-give-me-death.html. So all credits go to the author. I've noticed all examples of parametized sql queries have paremeter count limitations. An example is the one shown below.
SqlConnection conn = new SqlConnection(_connectionString);
conn.Open();
string s = "SELECT email, passwd, login_id, full_name FROM members WHERE email = #email";
SqlCommand cmd = new SqlCommand(s);
cmd.Parameters.Add("#email", email);
SqlDataReader reader = cmd.ExecuteReader();
This is just equivalent to
SELECT email, passwd, login_id, full_name FROM members WHERE email = 'x';
I've learned programming all on my own through reading online tutorials and I really got nobody to help me on this. The reason I got stuck with full sql statement queries is the fact that I can't figure out how to do parametized sql queries with unlimited parameters. Is there any way to do this? The example only accepts 1 parameter which is the 'email' field. And it selects 4 fields from the given sql statement. My question is... is there any way we can do parametized sql queries with 5, 6, 7, or 100 selected fields, as well as the conditions under the WHERE clause? If this is possible, it will be particularly helpful when using INSERT statement. Thank you very much.
This example is in C#, but any VB.NET or same C# implementations are greatly appreciated. Thanks.
One possible solution would be to pass the parameters name and value using a Dictionary object. A Dictionary object holds a collection of keys and values, and this is exactly what a single SqlParameter is - a single Key/Value container in the form:
Key = #Value
A collection can hold an arbitrary count of items, for example:
new Dictionary<String, Object>
{
{ "#Name", "Anonymous" },
{ "#Age", 25 },
{ "#Street", "Highway" },
{ "#Number", "1001" },
{ "#City", "NoName" }
}
In the example above, the key is of type String and the value of type Object. Object allows parameter values of arbitrary types (the explanation comes later in the code examples).
One possibility to create dynamic SQL statements would be:
extract the repetitive tasks, for example the creation of the SqlCommand and the passing of the parameters to the SqlCommand variable
create parametrised dynamic SQL query string for the wanted SQL command
The code can look like this:
// extract all repetitive tasks
// Create an array of SqlParameters from the given Dictionary object.
// The parameter value is of type Object in order to allow parameter values of arbitrary types!
// The .NET Framework converts the value automatically to the correct DB type.
// MSDN info: http://msdn.microsoft.com/en-us/library/0881fz2y%28v=vs.110%29.aspx
private SqlParameter[] dictionaryToSqlParameterArray(Dictionary<string, object> parameters)
{
var sqlParameterCollection = new List<SqlParameter>();
foreach (var parameter in parameters)
{
sqlParameterCollection.Add(new SqlParameter(parameter.Key, parameter.Value));
}
return sqlParameterCollection.ToArray();
}
// sqlQuery is the complete parametrised query
// for example like: INSERT INTO People(Name, Age, Street) VALUES(#Name, #Age, #Street)
private SqlCommand createSqlCommand(String sqlQuery, Dictionary<String, object> parameters)
{
SqlCommand command = new SqlCommand(sqlQuery);
command.Parameters.AddRange(dictionaryToSqlParameterArray(parameters));
return command;
}
Now a call with dynamic count of parameters will look like this:
SqlConnection connection = new SqlConnection(connectionString);
connection.Open();
string sqlQuery = "SELECT email, passwd, login_id, full_name FROM members WHERE email = #email AND name = #name";
// using the newly created method instead of adding/writing every single parameter manually
SqlCommand command = createSqlCommand(sqlQuery, new Dictionary<String, Object>
{
{ "#email", "test#test.com" },
{ "#name", "test" }
});
SqlDataReader reader = command.ExecuteReader();
It is a good start, but this is still not very dynamic, since we need to write the complete query every time (we save only the typing of command.Parameters.Add). Let's change this in order to type even less:
// create a parametrised SQL insert command with arbitrary count of parameters for the given table
private SqlCommand createSqlInsert(String tableName, Dictionary<String, object> parameters)
{
// the sql insert command pattern
var insertQuery = #"INSERT INTO {0}({1}) VALUES({2})";
// comma separated column names like: Column1, Column2, Column3, etc.
var columnNames = parameters.Select (p => p.Key.Substring(1)).Aggregate ((h, t) => String.Format("{0}, {1}", h, t));
// comma separated parameter names like: #Parameter1, #Parameter2, etc.
var parameterNames = parameters.Select (p => p.Key).Aggregate ((h, t) => String.Format("{0}, {1}", h, t));
// build the complete query
var sqlQuery = String.Format(insertQuery, tableName, columnNames, parameterNames);
// debug
Console.WriteLine(sqlQuery);
// return the new dynamic query
return createSqlCommand(sqlQuery, parameters);
}
// create a parametrised SQL select/where command with arbitrary count of parameters for the given table
private SqlCommand createSqlWhere(String tableName, Dictionary<String, object> parameters)
{
// the sql select command pattern
var whereQuery = #"SELECT * FROM {0} WHERE {1}";
// sql where condition like: Column1 = #Parameter1 AND Column2 = #Parameter2 etc.
var whereCondition = parameters.Select (p => String.Format("{0} = {1}", p.Key.Substring(1), p.Key)).Aggregate ((h, t) => String.Format("{0} AND {1}", h, t));
// build the complete condition
var sqlQuery = String.Format(whereQuery, tableName, whereCondition);
// debug
Console.WriteLine(sqlQuery);
// return the new dynamic query
return createSqlCommand(sqlQuery, parameters);
}
Now the creation of a SELECT command will look like this:
SqlConnection connection = new SqlConnection(connectionString);
connection.Open();
// specify only table name and arbitrary count of parameters
var getPersonSqlCommand = createSqlWhere("People", new Dictionary<String, Object>
{
{ "#Name", "J.D." },
{ "#Age", 30 }
});
SqlDataReader reader = getPersonSqlCommand.ExecuteReader();
The createSqlWhere method will return an initialized SqlCommand with the query:
SELECT * FROM People WHERE Name = #Name AND Age = #Age
The INSERT will also be short:
SqlConnection connection = new SqlConnection(connectionString);
connection.Open();
// specify only table name and arbitrary count of parameters
var addPersonSqlCommand = createSqlInsert("People", new Dictionary<String, Object>
{
{ "#Name", "Anonymous" },
{ "#Age", 25 },
{ "#Street", "Test" }
});
addPersonSqlCommand.ExecuteNonQuery();
The corresponding SQL command will look like this:
INSERT INTO People(Name, Age, Street) VALUES(#Name, #Age, #Street)
Other SQL commands like DELETE, UPDATE and so on can be created in the same way. New parameters should be added only in one place - in the dictionary.
Admittedly the initial effort is more than just writing one method, but it will pay off if the new methods are used more than once (a couple of times) - for example five parametrised selects and/or inserts on five different tables with different parameters, which is certainly always the case in small and average sized software projects.
Just create a method like :
public void unlimQuery(string query,params object[] args)
{
SqlConnection conn = new SqlConnection(_connectionString);
conn.Open();
string s =query;
SqlCommand cmd = new SqlCommand(s);
For(int i=0;i< args.Length;i++)
cmd.Parameters.Add("#param"+i, args[i]);
SqlDataReader reader = cmd.ExecuteReader();
}
Example :
unlimQuery("INSERT INTO CUSTOMERS(ID,NAME,AGE,ADRESS,COUNTRY) VALUES(#param0,#param1,#param2,#param3,#param4)",5,"Ali",27,"my City","England");
Explanation :
the params keyword in c# gives you the possibility to insert unlimited arguments of the indicated type, so the arguments added (5,"Ali",27,"my City","England") will be casted to an array of objects then passed to the Method
inside the method you'll get an array of objects, so for each object you create a parameter, his alias is #paramX where X is the index of the argument (in the params array), then sqlCommad will replace each alias by its value defined in the cmd.Parameters.Add("#param"+i, args[i]) clause
so #param0 => 5, .....
i think you just have to change this
cmd.Parameters.Add("#email", email);
to
cmd.Parameters.AddWithValue("#email", email);
I have never learned this aspect of programming, but is there a way to get each separate result of a excel query(using OleDB) or the likes.
The only way I can think of doing this is to use the INTO keyword in the SQL statement, but this does not work for me (SELECT attribute INTO variable FROM table).
An example would be to use the select statement to retrieve the ID of Clients, and then compare these ID's to clientID's in a client ListArray, and if they match, then the clientTotal orders should be compared.
Could someone prove some reading material and/or some example code for this problem.
Thank you.
This code fetches rows from a sql procedure. Will probably work for you too with some
modifications.
using (var Conn = new SqlConnection(ConnectString))
{
Conn.Open();
try
{
using (var cmd = new SqlCommand("THEPROCEDUREQUERY", Conn))
{
cmd.CommandType = CommandType.StoredProcedure;
SqlDataReader reader = cmd.ExecuteReader();
// Find Id of column in query only once at start
var Col1IdOrd = reader.GetOrdinal("ColumnName");
var Col2IdOrd = reader.GetOrdinal("ColumnName");
// loop through all the rows
while (reader.Read())
{
// get data for each row
var Col1 = reader.GetInt32(ColIdOrd);
var Col2 = reader.GetDouble(Col2IdOrd);
// Do something with data from one row for both columns here
}
}
}
finally
{
Conn.Close();
}