I can't seem to get this working:
My table column headers are 'genre' 'artist' 'album'
and the params I'm passing in are (type, filter, value) ("artist", "genre", "Rock") where there are two rows in the db with "Rock" for the genre.
When I follow the debugger, the 'while (reader.Read())' must return false because the loop is never entered and thus nothing written to the List.
public static List<String> getWithFilter(String type, String filter, String value)
{
List<String> columnData = new List<String>();
string query = "SELECT #type FROM Music WHERE" +
" #filter = '#value'";
SqlConnection connection = Database.GetConnection();
SqlCommand getData = new SqlCommand(query, connection);
getData.Parameters.AddWithValue("#type", type);
getData.Parameters.AddWithValue("#filter", filter);
getData.Parameters.AddWithValue("#value", value);
connection.Open();
using (connection)
{
using (getData)
{
using (SqlDataReader reader = getData.ExecuteReader())
{
while (reader.Read())
{
columnData.Add(reader.GetString(0));
}
}
}
}
return columnData;
}
You cannot use parameters for the names of columns and you don't put quotes around them when using them. Right now your query is the equivalent of
SELECT 'artist' FROM Music WHERE 'genre' = '#value'
You can do the following instead.
string query = "SELECT " + type + " FROM Music WHERE " + filter + " = #value";
And just remove the lines that create the #type and #fitler parameters.
You're looking either for formatting or string interpolation (requires C# 6.0):
string query =
$#"SELECT {type}
FROM Music
WHERE {filter} = #value";
...
getData.Parameters.AddWithValue("#value", value);
Formatting is a bit more wordy:
string query = String.Format(
#"SELECT {0}
FROM Music
WHERE {1} = #value", type, filter);
I assuming that you're using .net 2
DateTime current = DateTime.Now;
Console.WriteLine(current);
SqlConnection conn = new SqlConnection();
string q = "SELECT #field FROM student";
SqlDataAdapter da = new SqlDataAdapter(q, conn);
da.SelectCommand.Parameters.AddWithValue("#field", "snName");
DataTable dt = new System.Data.DataTable();
conn.Open();
da.Fill(dt);
conn.Close();
List<string> names = new List<string>();
foreach (DataRow dr in dt.Rows)
{
names.Add(dr[0].ToString());
}
Console.WriteLine("Fetching {0} data for {1}", names.Count, DateTime.Now - current);
Console.ReadKey();
You can use lambda expression to mapping the datatable in .net >4
Related
I am creating a SQLConnection to access some data. I need to print the entire DB result in log
I can able to print the specific cell value by referring out the cell, but I want to print the query result at single shot
string queryString = "select top 1 column_1, column_2 from master_table";
using (SqlConnection dbConnection = new SqlConnection(envDBConnectionString))
{
SqlCommand dbCommand = new SqlCommand(queryString, dbConnection);
dbConnection.Open();
SqlDataReader dbReader = dbCommand.ExecuteReader();
if (dbReader.HasRows)
{
while (dbReader.Read())
{
string col1Value = dbReader.GetValue(0).ToString());
string col2Value = dbReader.GetValue(1).ToString());
}
}
dbReader.Close();
dbConnection.Close();
}
Here I am getting each column value and stores it to string variable. instead I want to store the entire query result in that string
I suggest method extracting, i.e.
// Given a query, return records
private static IEnumerable<IDataRecord> QueryLines(string query) {
using (SqlConnection con = new SqlConnection(envDBConnectionString)) {
con.Open();
using (var q = new SqlCommand(query, con)) {
using (var reader = q.ExecuteReader()) {
while (reader.Read())
yield return reader as IDataRecord;
}
}
}
}
Then we can easily use it:
string command =
#"select top 1
column_1 as Column1,
column_2 as Column2
from master_table";
Having records, write them into a log in a desired format, e.g. simple CSV
File.AppendAllLines(#"c:\MyLog.txt", QueryLines(command)
.Select(record => $"{record[0]},{record[1]}"));
Or in elaborated XML
File.AppendAllLines(#"c:\MyLog.txt", QueryLines(command)
.Select(record => string.Concat(Enumerable
.Range(0, record.FieldCount)
.Select(i => $"<{record.GetName(i)}>{record[i]}</{record.GetName(i)}>")));
string queryString = "select top 1 column_1, column_2 from master_table";
using (SqlConnection dbConnection = new SqlConnection(envDBConnectionString))
{
SqlCommand dbCommand = new SqlCommand(queryString, dbConnection);
SqlDataAdapter sa = new SqlDataAdapter(dbCommand);
DataTable dt = new DataTable(); //All your data in this datatable
sa.fill(dt);
}
for reference:
Inside loop:
foreach(DataRow row in dt.rows){
row["COLUMN_NAME"].toString(); //or whatever datatype
}
Update: as the original question was essentially answered, I've marked this as complete.
I have a C# project in which I'd like to query a database. The SQL query will SELECT from a table, and in the WHERE clause I want to filter the results from a pre-defined list of values specified in C#.
List<string> productNames = new List<string >() { "A", "B", "C" };
foreach (name in productNames)
{
string query = #"
SELECT *
FROM products
WHERE name IN (#name);";
// Execute query
MySqlCommand cmd = new MySqlCommand(query, dbConn);
cmd.Parameters.AddWithValue("name", name);
MySqlDataReader row = cmd.ExecuteReader();
while (row.Read())
{
// Process result
// ...
}
}
However I'm getting an error:
There is already an open DataReader associated with this Connection
which must be closed first
Is it not possible then to use a for loop to add parameters this way to a SELECT statement?
You need to dispose your object to not get the exception. However you don't need to iterate over values and run a query for every value in the list. Try the following code. It makes a parameter for every value and adds it to command to use in "IN (...)" clause.
Also "using" keywords handles disposing objects.
List<string> productsIds = new List<string>() { "23", "46", "76", "88" };
string query = #"
SELECT *
FROM products
WHERE id IN ({0});";
// Execute query
using (MySqlCommand cmd = new MySqlCommand(query, dbConn))
{
int index = 0;
string sqlWhere = string.Empty;
foreach (string id in productsIds)
{
string parameterName = "#productId" + index++;
sqlWhere += string.IsNullOrWhiteSpace(sqlWhere) ? parameterName : ", " + parameterName;
cmd.Parameters.AddWithValue(parameterName, id);
}
query = string.Format(query, sqlWhere);
cmd.CommandText = query;
using (MySqlDataReader row = cmd.ExecuteReader())
{
while (row.Read())
{
// Process result
// ...
}
}
}
You are doing few things wrong. Let me point out them:
Everything is fine in the first iteration of the loop, when you are in second iteration the First Reader associated with the command remains opened and that result in current error.
You are using Where IN(..) you you can specify the values within IN as comma separated so there is no need to iterate through parameters.
You can use String.Join method to construct this values with a comma separator.
Now take a look into the following code:
List<int> productsIds = new List<int>() { 23, 46, 76, 88 };
string idInParameter = String.Join(",", productsIds);
// Create id as comma separated string
string query = "SELECT * FROM products WHERE id IN (#productId);";
MySqlCommand cmd = new MySqlCommand(query, dbConn);
cmd.Parameters.AddWithValue("#productId", idInParameter);
MySqlDataReader row = cmd.ExecuteReader();
while (row.Read())
{
// Process result
// ...
}
Please note if the id field in the table is not integers then you have to modify the construction of idInParameter as like the following:
idInParameter = String.Join(",", productsIds.Select(x => "'" + x.ToString() + "'").ToArray());
Pass the comma separated productIds string instead of looping. Read more about IN here.
string productIdsCommaSeparated = string.Join(",", productsIds.Select(n => n.ToString()).ToArray())
string query = #"
SELECT *
FROM products
WHERE id IN (#productId);";
// Execute query
MySqlCommand cmd = new MySqlCommand(query, dbConn);
cmd.Parameters.AddWithValue("productId", productIdsCommaSeparated );
MySqlDataReader row = cmd.ExecuteReader();
while (row.Read())
{
// Process result
// ...
}
The error you are getting is because you do not close the MySqlDataReader. You must close it to get rid of error before you call ExecuteReader in next iteration but this is not proper way in this case.
From what I tried and tested seems best solution (especially for text column types) is to create a list of individual parameters and add it as a range the to the query and parameters.
e.g:
List<MySqlParameter> listParams = new List<MySqlParameter>();
for (int i = 0; i < listOfValues.Length; i++)
{
listParams.Add(new MySqlParameter(string.Format("#values{0}", i),
MySqlDbType.VarChar) { Value = listOfValues[i] });
}
string sqlCommand = string.Format("SELECT data FROM table WHERE column IN ({0})",
string.Join(",", listParams.Select(x => x.ParameterName)));
......
using (MySqlCommand command = new MySqlCommand(sqlCommand, connection)
{
............
command.Parameters.AddRange(listParams.ToArray());
............
}
I am trying to filter my gridview on the basis of checkboxlist selected.
So here is what I tried
string constr = ConfigurationManager.ConnectionStrings["OracleConn"].ConnectionString;
string strQuery = "select sr_no, type, stage, ref_no, ref_date, party_name, amount, remarks, exp_type, " +
"voucher_no, cheque_no,cheque_dt, chq_favr_name from XXCUS.XXACL_PN_EXPENSE_INFO";
string condition = string.Empty;
foreach (ListItem li in ddlStatus.Items)
{
condition += li.Selected ? string.Format("'{0}',", li.Value) : string.Empty;
if (!string.IsNullOrEmpty(condition))
{
condition += string.Format(" Where type IN ({0})", condition.Substring(0, condition.Length - 1));
}
using (OracleConnection conn = new OracleConnection(constr))
{
using (OracleCommand cmd = new OracleCommand(strQuery + condition))
{
using (OracleDataAdapter sda = new OracleDataAdapter(cmd))
{
cmd.Connection = conn;
using (DataTable dtcheck = new DataTable())
{
sda.Fill(dtcheck);
GridExpInfo.DataSource = dtcheck;
GridExpInfo.DataBind();
}
}
}
}
but I am getting error as
ORA-00933: SQL command not properly ended
My debugged query is
select sr_no, type, stage, ref_no, ref_date, party_name, amount, remarks, exp_type, voucher_no, cheque_no,cheque_dt, chq_favr_name
from XXCUS.XXACL_PN_EXPENSE_INFO'10',
Where type IN ('10')
I took reference from here
You should prepare the where condition using a List of strings and run the query after you have completed the query builder phase.
// Create a list of your conditions to put inside the IN statement
List<string>conditions = new List<string>();
foreach (ListItem li in ddlStatus.Items)
{
if(li.Selected)
conditions.Add($"'{li.Value}'");
}
// Now build the where condition used
string whereCondition = string.Empty;
if (condition.Count > 0)
{
// This produces something like "WHERE type in ('10', '11', '12')"
// The values for the IN are directly concatenated together
whereCondition = " Where type IN (" + string.Join(",", conditions) + ")";
}
using (OracleConnection conn = new OracleConnection(constr))
{
using (OracleCommand cmd = new OracleCommand(strQuery + whereCondition))
{
....
Consider that this approach is very exposed to Sql Injection attacks and to a parsing problems if your selected values are strings containing quotes
Instead if you start using parameters then your code should be changed to
int count = 1;
List<OracleParameter> parameters = new List<OracleParameter>();
List<string>conditions = new List<string>();
foreach (ListItem li in ddlStatus.Items)
{
if(li.Selected)
{
// parameters are named :p1, :p2, :p3 etc...
conditions.Add($":p{count}");
// Prepare a parameter with the same name of its placeholder and
// with the exact datatype expected by the column Type, assign to
// it the value and add the parameter to the list
OracleParameter p = new OracleParameter($":p{count}",OracleType.NVarChar);
p.Value = li.Value;
parameters.Add(p);
count ++;
}
}
if (condition.Count > 0)
{
// This produces something like "WHERE type in (:p1, :p2, :p3)"
// The values are stored before in the parameter list
whereCondition = " Where type IN (" + string.Join(",", conditions) + ")";
}
using (OracleConnection conn = new OracleConnection(constr))
{
using (OracleCommand cmd = new OracleCommand(strQuery + whereCondition))
{
// Add the parameters with the expected names, type and value.
cmd.Parameters.AddRange(parameters.ToArray());
....
It is a little more lines but this prevents Sql Injection and there is no more problem in parsing strings
I am passing a long list of employeeIds to employeeIdlist and I split them into a List. Using this list I am adding parameters to my query.
I am getting the following error
{"Must declare the scalar variable \"#EmployeeId\"."}
public List<versionInfo> GetVersion(string employeeIdlist)
{
DbHelper helper = new DbHelper();
List<versionInfo> empVerInfo = new List<versionInfo>();
using (SqlConnection conn = new SqlConnection(connString))
{
conn.Open();
using (SqlCommand getVersion = new SqlCommand())
{
getVersion.Connection = conn;
getVersion.CommandText = #"SELECT EmployeeId,Version
FROM [dbo].[EmployeeVersion]
WHERE EmployeeId in (#EmployeeId)";
getVersion.CommandType = CommandType.Text;
List<int> empIds = employeeIdlist.Split(',').Select(int.Parse).ToList();
StringBuilder sb = new StringBuilder();
int i = 0;
foreach (var emp in empIds)
{
// IN clause
sb.Append("#EmployeeId" + i.ToString() + ",");
// parameter
getVersion.Parameters.AddWithValue("#EmployeeId" + i.ToString(), emp);
i++;
}
// getVersion.Parameters.AddWithValue("#EmployeeId", employeeIdlist);
SqlDataReader rdr = getVersion.ExecuteReader();
while (rdr.Read())
{
versionInfo vi = new versionInfo();
vi.employeeId = helper.GetDb<int>(rdr, "EmployeeId");
vi.version = helper.GetDb<decimal>(rdr, "Version");
empVerInfo.Add(vi);
}
rdr.Close();
}
conn.Close();
}
return empVerInfo;
}
Remove the text after the IN
getVersion.CommandText = #"SELECT EmployeeId,Version
FROM [dbo].[EmployeeVersion]
WHERE EmployeeId in (";
then the foreach could build the full list of parameters and texts
foreach (var emp in empIds)
{
sb.Append("#EmployeeId" + i.ToString() + ",");
getVersion.Parameters.AddWithValue("#EmployeeId" + i.ToString(), emp);
i++;
}
after exiting the loop remove the last comma from the StringBuilder
sb.Length--;
finally, complete the command text appending the content of the StringBuilder and do not forget the closing parenthesys for the IN clause.
getVersion.CommandText += sb.ToString() + ")";
Now you can run the command with the correct IN clause and a matching list of parameters
If fails because your string query has one parameter named #EmployeeId and your Command object has many parameters with different names ("#EmployeeId1" is not equal to "#EmployeeId")
It seems like you are trying to apply this approach, which is a good idea.
You are two lines away of getting it to work:
Add this lines:
sb.Lenght--;
getVersion.CommandText = getVersion.CommandText.Replace("#EmployeeId",sb.ToString())
just before:
SqlDataReader rdr = getVersion.ExecuteReader();
After doing that your added parameters will match those #parameters existing in the sql string.
This is just another option. You can achieve the same result in 3 lines of code using Dapper ORM used in Stack Overflow.
You can download via NuGet.
public class VersionInfo
{
public int EmployeeId { get; set; }
public decimal Version { get; set; }
}
class Program
{
public static string connString = "...";
static void Main(string[] args)
{
var result = GetVersion(new List<int> {1, 2});
Console.ReadLine();
}
public static List<VersionInfo> GetVersion(IList<int> employeeIds)
{
using (IDbConnection conn = new SqlConnection(connString))
{
conn.Open();
var entities = conn.Query<VersionInfo>(
#"SELECT EmployeeId, Version from EmployeeVersion WHERE EmployeeId IN #EmployeeIds",
new {EmployeeIds = employeeIds});
return entities.ToList();
}
}
}
On your select statement you have to declare a value for your variable. I have made it an Integer. If it is a text value, then you can use varchar(25).
#"DECLARE #EmployeeId INT
SELECT EmployeeId,Version
FROM [dbo].[EmployeeVersion]
WHERE EmployeeId in (#EmployeeId)";
hello i build a webservice in visual studio 2010. i get some id's which are saved in a string looks like this:
string room_ids="5,11,99,42";
they are separated by comma. i created a foreach loop to split the ids and from the comma and use them in my sql query until the ids are finished. but it doesn't work. i get an error it says:
Error converting data type nvarchar to numeric
here is my code, thanks in advance for your help!
internal static List<RAUM> Raum(string RAUMKLASSE_ID, string STADT_ID, string GEBAEUDE_ID, string REGION_ID)
{
List<RAUM> strasseObject = new List<RAUM>();
string[] allegebaude = GEBAEUDE_ID.Split(new char[] { ',' });
foreach (string gebaudeid in allegebaude)
{
Trace.WriteLine("SIND JETZT DRINNE");
Trace.WriteLine(gebaudeid);
using (SqlConnection con = new SqlConnection(#"Data Source=Localhost\SQLEXPRESS;Initial Catalog=BOOK-IT-V2;Integrated Security=true;"))
using (SqlCommand cmd = new SqlCommand(#"SELECT r.BEZEICHNUNG AS BEZEICHNUNG, r.ID AS ID FROM RAUM r WHERE RAUMKLASSE_ID = ISNULL(#Raumklasse_ID, RAUMKLASSE_ID) AND STADT_ID = ISNULL(#Stadt_ID, STADT_ID) AND GEBAEUDE_ID = ISNULL(#gebaudeid,GEBAEUDE_ID ) AND REGION_ID = ISNULL(#Region_ID, REGION_ID)", con))
{
con.Open();
if (!StringExtensions.IsNullOrWhiteSpace(RAUMKLASSE_ID))
cmd.Parameters.AddWithValue("#Raumklasse_ID", RAUMKLASSE_ID);
else
cmd.Parameters.AddWithValue("#Raumklasse_ID", DBNull.Value);
if (!StringExtensions.IsNullOrWhiteSpace(STADT_ID))
cmd.Parameters.AddWithValue("#Stadt_ID", STADT_ID);
else
cmd.Parameters.AddWithValue("#Stadt_ID", DBNull.Value);
if (!StringExtensions.IsNullOrWhiteSpace(GEBAEUDE_ID))
cmd.Parameters.AddWithValue("#gebaudeid", GEBAEUDE_ID);
else
cmd.Parameters.AddWithValue("#gebaudeid", DBNull.Value);
if (!StringExtensions.IsNullOrWhiteSpace(REGION_ID))
cmd.Parameters.AddWithValue("#Region_ID", REGION_ID);
else
cmd.Parameters.AddWithValue("#Region_ID", DBNull.Value);
using (SqlDataReader rdr = cmd.ExecuteReader())
{
while (rdr.Read())
{
if (rdr["BEZEICHNUNG"] != DBNull.Value && rdr["ID"] != DBNull.Value)
{
strasseObject.Add(new RAUM()
{
RaumName = rdr["BEZEICHNUNG"].ToString(),
RaumID = rdr["ID"].ToString()
});
}
}
}
}
}
return strasseObject;
}
If you already have the IDs in a comma-separated string (called IDstring) then you can just do something like this:
sqlQuery = "SELECT Columns FROM table WHERE ID IN (" + IDstring + ")";
In your specific case, don't split the original string (GEBAEUDE_ID) but use it as it is:
// Don't use a foreach loop any more
string gebaudeIdSection = " AND GEBAEUDE_ID IN (" + GEBAEUDE_ID + ") ";
if (string.IsNullOrEmpty(GEBAUDE_ID)) { gebaudeIdSection = ""; } // if there are no ids, let's remove that part of the query completely.
using (SqlConnection con = new SqlConnection(#"Data Source=Localhost\SQLEXPRESS;Initial Catalog=BOOK-IT-V2;Integrated Security=true;"))
using (SqlCommand cmd = new SqlCommand(#"SELECT r.BEZEICHNUNG AS BEZEICHNUNG, r.ID AS ID FROM RAUM r WHERE RAUMKLASSE_ID = ISNULL(#Raumklasse_ID, RAUMKLASSE_ID) AND STADT_ID = ISNULL(#Stadt_ID, STADT_ID)" + gebaudeIdSection + " AND REGION_ID = ISNULL(#Region_ID, REGION_ID)", con))
{ // The rest of the code is the same as before...
First of all I think you have to correct:
cmd.Parameters.AddWithValue("#gebaudeid", GEBAEUDE_ID);
with:
cmd.Parameters.AddWithValue("#gebaudeid", gebaudeid);
Then, try to convert the ids into integers ( for example, using Convert.ToInt32(gebaudeid) ) and not to pass them as strings in AddWithValue method.
try this:
if (!StringExtensions.IsNullOrWhiteSpace(gebaudeid))
cmd.Parameters.AddWithValue("#gebaudeid", Convert.ToInt32(gebaudeid));
you should also pass the right parameter to your AddWithValue statement. You are iterating over the list of your ID's, that list being allegebaude. So you have to pass the gebaudeid parameter to your statement, instead of what you're doing now.
You can't implicitly treat a comma separated list of values; instead you'll need to create a table values function to split the list of values into a table structure and then use this structure as you would normally.
Have a look at this question: INSERT INTO TABLE from comma separated varchar-list for a sample function.