My issue is that the results are empty when executing the statement, even though when executing it in Microsoft's SQL server studio it works.
//This has two values in it (Ex: 4 and 2)
string[] arr2 = groupListValues.Split('-');
List<string> userID = new List<string>();
// Connect to the database
SqlConnection gconn = new SqlConnection(ConfigurationManager.ConnectionStrings["connectinfohere"].ConnectionString);
gconn.Open();
SqlCommand command1 = new SqlCommand();
command1.Connection = gconn;
String sql = "SELECT ID FROM Users WHERE Group = #groupID";
command1.CommandText = sql;
command1.Parameters.Add(new SqlParameter("#groupID", ""));
SqlDataReader reader = command1.ExecuteReader();
//issue is in this loop
foreach (string str in arr2)
{
command1.Parameters["#groupID"].Value = str;
while (reader.Read())
{
userID.Add(reader["ID"].ToString());
}
}
Not sure what the issue is. The "ID" I'm getting in the SQL statement is of type bigint, could that cause an issue?
The reason I am setting the parameter inside the foreach loop is because, for each value in arr2 corresponds to a group that several users could be attached to. So I need to loop through that, get the users attached to each groupID, then add all their ID's to a list.
There are two problems with you code:
The first one is that you setting the #groupID parameter after you execute the reader. To fix it, execute the reader after you set the parameter value like this:
foreach (string str in arr2)
{
command1.Parameters["#groupID"].Value = str;
using(SqlDataReader reader = command1.ExecuteReader())
{
while (reader.Read())
{
userID.Add(reader["ID"].ToString());
}
}
}
The second problem is that Group is a reserved keyword in SQL, so you need to wrap it with square brackets like this:
String sql = "SELECT ID FROM Users WHERE [Group] = #groupID";
Related
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 searching for a way to Execute Custom SQL Queries and to provide the result in JSON. Normally you have to provide a Class for the Query result e.g.
var query = dbConn.Query<ClassTypes>("Select a as key, b as value FROM table WHERE id = ?", new object[] { ObjectID });
But in my case, I don't know the SQL Statement, because its provided by an external JavaScript from a Webview.
This Webview might ask my application to Execute
Select a.col1 as foo,b.col1, a.col2 FROM table1 a INNER JOIN table2 b ON a.id=b.aid
And wants me to return:
foo:xxx
col2:yyy
Which columns are "asked" by the SQL Statement is completely free, or which aliases are used, I just want to execute the Statement an return key value pairs with the aliases or column names and the values in a JSON (for each row).
So I'm not able to prepare a custom Class for the Query, because I don't know the format of the SQL Query.
Does anyone have an idea?
I just want to execute the Statement an return key value pairs with the aliases or column names and the values in a JSON (for each row).
For your scenario, You could use SqlDataReader to approach, SqlDataReader contains GetName method that could use to get the column name as key, and it also contains GetSqlValue method that could retrieve column's value. If you can't confirm the field count, you could also use FieldCount to get current reader 's field counts
For example
using (SqlConnection conn = new SqlConnection(connectionString))
{
conn.Open();
if (conn.State == System.Data.ConnectionState.Open)
{
using (SqlCommand cmd = conn.CreateCommand())
{
cmd.CommandText = GetProductsQuery;
using (SqlDataReader reader = cmd.ExecuteReader())
{
var list = new List<Dictionary<string, object>>();
while (reader.Read())
{
var dict = new Dictionary<string, object>();
var i = 0;
do
{
var key = reader.GetName(i);
var value = reader.GetSqlValue(i);
dict.Add(key, value);
i++;
} while (i < reader.FieldCount);
list.Add(dict);
}
}
}
}
}
For more detail please refer this document.
I create an application using c# , In my authentification interface , i have a test control , i want to know profile user .
My database contains table named user which contains 4 columns
(id_user,name ,mail, profile)
Here is my code
public string profil_user(string login)
{
SqlConnection conn = new database().connect_user();
SqlCommand cmd = conn.CreateCommand();
cmd.CommandText = "select profile from user where name = '" + login + "';";
SqlDataReader s = cmd.ExecuteReader();
if (s.Read())
{
return ( s.GetString(3));
}
else{return ("false"); }
}
but i have an exception in s.GetString(3)
system.IndexOutOfRange : index was outside the bounds of the array
You're only selecting a single field (profile) but then you're trying to select the 4th field (index 3) here:
return ( s.GetString(3));
In addition to just returning s.GetString(0) I would strongly advise you to:
Use parameterized SQL - always do this, to prevent SQL injection attacks, make your code more readable, and prevent unexpected text conversion problems
Either throw an exception or return null if the profile isn't found, instead of returning the string "false"
Use using statements for disposable things like SqlCommand, SqlConnection and SqlDataReader to ensure that you clean up resources appropriately
Start following .NET naming conventions to make your code more idiomatic
So something like:
public string GetUserProfile(string login)
{
string sql = select profile from user where name = #login";
// I assume Connect() returns an *open* connection?
using (var conn = new Database().Connect())
{
using (var command = new SqlCommand(sql, conn))
{
command.Parameters.Add("#login", SqlDbType.NVarChar).Value = login;
using (var reader = command.ExecuteReader())
{
// If it's an error (code failure) for there to be no matching profile,
// you may want to throw an exception instead.
return s.Read() ? s.GetString(0) : null;
}
}
}
}
So you want the fourth row, not the fourth column which you try to access with s.GetString(3):
int rowNum = 0;
while(s.Read())
{
if(++rowNum == 4)
{
return s.GetString(0);
}
}
return "false";
However, it is a bit strange to access the fourth row when you don't use an Order By. You should also only return the row that you want with the correct sql query.
You are also open for sql injection if you use string concatenation here:
cmd.CommandText = "select profile from user where name = '" + login + "';";
Use sql parameters:
cmd.CommandText = "select profile from user where name = #login";
cmd.Parameters.Add("#login", SqlDbType.VarChar).Value = login;
have 4 columns not rows
Ok, so you instead want the fourth column. Why don't you use the name instead?
Since you only select the profile-column(the fourth), you could simply use GetString(0). But you could also select all columns and then determine the correct index with GetOrdinal:
int profileColumnIndex = s.GetOrdinal("profile");
return s.GetString(profileColumnIndex);
This is useful if you don't control the query or it might be changed in future.
You are selecting only 1 field, thus index 3 is out of bounds. It also very important to Use parameters. Try:
cmd.CommandText = "select profile from user where name = #login;";
cmd.Parameters.Add("#login, SqlDbType.NVarChar).Value = login;
SqlDataReader s = cmd.ExecuteReader();
while (s.Read())
{
return s[0].ToString();
}
The parameter for SqlDataReader.GetString should be the column index. You're only selecting one column so you get an exception.
Because you do not have all the fields in your select list
Change the SQL to:
select id_user,name ,mail, profile from user where name = '" + login + "';
I have to select user name from a database in SQL Server. The query that is generated by SqlCommand works in SQL Server Management Studio but not in my code.
And this only happens when the input is like AFFAQPC/affaq containing /.
The code is:
public int? getid()
{
SqlConnection Db = new SqlConnection(ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString);
Db.Open();
// Searching for id in Users table from the logged in username
SqlCommand command = new SqlCommand("SELECT TOP 1 id FROM UsersLogin where username = '#user1';", Db);
command.Parameters.AddWithValue("#user1", userName);
string query = command.CommandText;
foreach (SqlParameter p in command.Parameters)
{
query = query.Replace(p.ParameterName, p.Value.ToString());
}
Trace.WriteLine(query);
using (SqlDataReader reader = command.ExecuteReader())
{
if (reader.Read())
{
Trace.WriteLine("111");
int id = Convert.ToInt32(reader["id"]);
Trace.WriteLine(id);
Db.Close();
return id;
}
}
Db.Close();
return null;
}
The error occurs when input contains a /.
The query that is generated in SqlCommand:
SELECT TOP 1 id
FROM UsersLogin
WHERE username = 'AFFAQPC\affaq';
remove the single quotes from your query string
username = '#user1'
to
username = #user1
The "Parameter" should be WITHOUT the "#", just the name
command.Parameters.AddWithValue("user1", userName);
if the userName value is a string (confirming whatever your source is), that will be properly recognized when processed. You do not need to explicitly quote-it. Otherwise, the query is specifically looking for a user '#user1' which is probably why it is not returning what you expect.
I have NO idea why you are cycling through all parameters to assign the value... the userName field should already be good to go without doing your foreach parameter check.
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();
}