I'm trying to search in table(called Accounts) for Username and in the line of this user in coulmn 4 that called PhotoId there is string that i need to get and add it to empty string value that i made before. thats what i tryied
i want to do it by Query like my code
string ecid = e.CallbackQuery.Message.Chat.Id.ToString();
using (SqlCommand sqlCommand = new SqlCommand("SELECT * from Accounts where Username like #username", con))
{
con.Open();
sqlCommand.Parameters.AddWithValue("#username", ecid);
string variable;
string userfound = (string)sqlCommand.ExecuteScalar();
con.Close();
if (userfound == ecid)
{
using (SqlCommand GotPhoto = new SqlCommand("SELECT PhotoId from Accounts where Username like #user", con))
{
con.Open();
GotPhoto.Parameters.AddWithValue("#user", ecid);
DataPid = GotPhoto.ExecuteScalarAsync().ToString();
con.Close();
// await bot.SendPhotoAsync("xxx", DataPid, capo, parseMode: ParseMode.Markdown, replyMarkup: zz);
await bot.SendTextMessageAsync(cid, "its been Poster", parseMode: ParseMode.Html);
}
}
else
{
MessageBox.Show("Not Working");
}
}
You are combining a SELECT * ... with ExecuteScalar(), which "returns the value of the first column in the first row of the resultset. Additional rows and columns are ignored."(https://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlcommand.executescalar(v=vs.110).aspx). Probably username is not the first column in the accounts table, so the content of another column is retured and your comparison fails.
Use SELECT username from Accounts where Username like #username instead.
EDIT
Depending on your data-model you can also combine the two queries into one as you are querying the same row twice.
con.Open();
using (var cmd = new SqlCommand("SELECT PhotoId from Accounts where Username like #user", con)) {
cmd.Parameters.AddWithValue("#user", ecid);
using (var reader = await cmd.ExecuteReaderAsync()) {
if (!reader.HasRows || ! reader.Read()) {
MessageBox.Show("User not found");
} else {
DataPid = cmd.GetYOURDATATYPE(0).ToString();
//....
}
}
}
con.Close();
According to the documentation of 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.
When you perform string userfound = (string)sqlCommand.ExecuteScalar();
You are comparing the username to a value ( but wich one ? the value of the first column in the create table instruction)
I Suggest you change the first query to be sure to select username
PS:
To be consistant, you can also rename both of your query parameter #username instead of #user and #username because it refers exactly to the same thing.
You can perform only one query instead of two. ( select photoid ... where username = .. , and just check if the result contains one row )
Related
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 am working on a login page. I'd like to check if the username & password exists in the database. I have three database tables : Teams,Organizers,Admins with username & password field in each table respectively. I am implementing the login in three-tier architecture.
I believe that I have a problem with my SQL statement below. I tested my sql query with a distinct/valid team username and team password. The COUNT query returns more than one row, which is incorrect.
This are my codes for the data access layer :
public int getExistingAccount(string username, string password)
{
string queryStr = "SELECT COUNT(*) FROM Teams t,Organizers o,Admins a WHERE (t.teamUsername=#username AND t.teamPassword=#password) OR (o.organizerUsername=#username AND o.organizerPassword=#password) OR (a.adminUsername=#username AND a.adminPassword=#password)";
SqlConnection conn = new SqlConnection(_connStr);
SqlCommand cmd = new SqlCommand(queryStr, conn);
cmd.Parameters.AddWithValue("#username", username);
cmd.Parameters.AddWithValue("#password", password);
int returnValue = 0;
conn.Open();
returnValue = (int)cmd.ExecuteScalar();
conn.Close();
return returnValue;
}
As for the business logic layer codes :
public string getAccount(string username, string password)
{
string returnMessage = "";
if (username.Length == 0)
returnMessage += "Username cannot empty</br>";
if (password.Length == 0)
returnMessage += "Password cannot be empty</br>";
if (username.Equals(password))
{
returnMessage += "Duplicate value. Please try again</br>";
}
//Invoke validateInput() method to validate data
if (returnMessage.Length == 0)
{
int noOfRows = 0;
LogAccounts logInd = new LogAccounts();
noOfRows = logInd.getExistingAccount(username, password);
if (noOfRows > 0)
returnMessage += "Account found";
else
returnMessage += "Invalid username/password.";
}
return returnMessage;
}
Try this, select from each table and UNION ALL the results, then count the rows.
select count(*) from
(
SELECT 1 as dummyname FROM Teams t
WHERE (t.teamUsername=#username AND t.teamPassword=#password)
union all
SELECT 1 FROM Organizers o
WHERE (o.organizerUsername=#username AND o.organizerPassword=#password)
UNION ALL
select 1 from Admnis
WHERE (a.adminUsername=#username AND a.adminPassword=#password)
)
I seems you have a really awkward database design, where fetching a single user requires a unnaturally large/long sql query.
In almost every use case you would have a single Users table, and if you need to tie the user to some additional information, you would have a reference to the user table by the UserId. You should read up on foreign keys aswell.
Quick sample:
Users:
- UserId (int or guid) (primary key)
- .... (additional fields removed for brewity)
The other tables would refer to the UserId column, and use that to pull information about the user with a join.
E.g.: SELECT T.*, U.* FROM Teams T INNER JOIN Users U ON U.UserId = T.UserId WHERE U.Username = "AwesomeCoach";
A simple validate query would be something like this:
SELECT COUNT(*) FROM Users WHERE Username = xx AND Password = xx
That would return an integer that specifies how many rows that matched the given username/password combination. It should be either 1 or 0. Put a Unique contraint on the Username column to ensure that there are only one occurence of each Username.
Footnote: I see that you have got an answer that solves the problem you were facing, but I would recommend that you read up on some database design, and try to keep it as simple as possible. Managing multiple users across multiple tables can and will be a hassle as the application grows.
Your design is really bad, you should have all users in one table. After that if you want to take user by id, you should check 3 diff tables. Anyway the problem is in the query you should write it like this:
string queryStr = #"
SELECT
COUNT(*) AS TeamsCount,
(SELECT COUNT(*) Organizers WHERE organizerUsername=#username AND organizerPassword=#password) AS OrgCount,
(SELECT Count(*) Admins WHERE adminUsername=#username AND adminPassword=#password) AS AdminCount
FROM
Teams
WHERE
teamUsername=#username AND
teamPassword=#password";
The query should look something like this. After that you need to return this in DataSet. You need:
DataSet dst = new DataSet();
using(SqlAdapter adapter = new SqlAdapter(cmd))
{
adapter.Fill(dst);
}
In this case you will have dst with 3 columns in it. Check for existing user should be:
if(dst.Tables[0].Rows[0]["TeamsCount"] > 0 ||
dst.Tables[0].Rows[0]["OrgCount"] > 0 ||
dst.Tables[0].Rows[0]["AdminCount"] > 0)
{
//user already exist !
}
I have two text boxes in my winform. I would like to enter a userId into first text box, after that by clicking a button display a User Name in the second text box properly. The data is stored in sql server compact. Table name is Users, and this table contains two columns UserID and UserName.
With this code I can open a connection and retrieve the first value from the UserName column,
SqlCeConnection cn = new SqlCeConnection(#"Data Source = D:\Database\Training.sdf");
try
{
cn.Open();
SqlCeCommand cmd = new SqlCeCommand("SELECT UserID, UserName from Users;", cn);
TrainerNameBox.Text = cmd.ExecuteScalar().ToString();
cn.Close();
}
catch
{
}
ExecuteScalar returns first column of the first row. Other columns or rows are ignored.
In your case, your first column is UserID. That's why you get first value of this column.
If you want to get UserName value, you might need to change your query like;
SELECT UserName from Users
And looks like you forget to use WHERE clause in your query since you want to get UserName from UserID. You might need to use using statement to dispose your SqlCeConnection and SqlCeCommand.
Full example;
using(SqlCeConnection cn = new SqlCeConnection(#"Data Source = D:\Database\Training.sdf"))
using(SqlCeCommand cmd = cn.CreateCommand())
{
cmd.CommandText = "SELECT UserName from Users WHERE UserID = #id";
cmd.Parameters.AddWithValue("#id", (int)txtUserID.Text);
cn.Open();
TrainerNameBox.Text = cmd.ExecuteScalar().ToString();
}
You are missing the WHERE clause to isolate the username that you want to display
int userID;
if(!Int32.TryParse(txtUserID.Text, out userID))
{
MessageBox.Show("Invalid User ID number");
return;
}
using(SqlCeConnection cn = new SqlCeConnection(#"Data Source = D:\Database\Training.sdf"))
using(SqlCeCommand cmd = new SqlCeCommand("SELECT UserName from Users WHERE UserID=#id;", cn))
{
cn.Open();
cmd.Parameters.AddWithValue("#id", userID);
object result = cmd.ExecuteScalar();
if(result != null)
TrainerNameBox.Text = result.ToString();
else
MessageBox.Show("No user for ID=" + userID.ToString());
}
Notice that ExecuteScalar returns the first column of the first row, so you need to remove the UserID field from your query and if, the user is not found, you need to check for a null return.
Applying directly the ToString() method to your ExecuteScalar could raise an exception if your user types an invalid id. There is also the problem to validate the user input. If you type a not numeric value for the user id, the conversion will fail. In this case you need to check the input using Int32.TryParse
Try this:
Dataset ds = cmd.ExecuteDataset().ToString();
TrainerNameBox.Text = ds.tables[0].Rows[0][1].toString();
TrainerIDBox.Text = ds.tables[0].Rows[0][0].toString();
I have a web application that writes to several databases for tracking employee change requests. I am running into a problem with entering in a new employee. They are first written to main Employee database before their access information is written to the other databases with EMP_ID being the primary key. When it goes to write to the other databases EMP_ID has been generated yet so it is getting entered in as 0.
To resolve this I was trying to loop and check the EMP_ID value until a value is generated but I continue to get stuck in a loop because the query returns back that no value was found.
while (int.Parse(empIDChecker) == 0)
{
dbConnection.Open();
validateIDSQLString = "SELECT EMP_ID FROM EMPLOYEE_TABLE WHERE FIRST_NAME = '" + firstNameTextBox.Text.Trim() + "' AND LAST_NAME = '" + lastNameTextBox.Text.Trim() + "'";
SqlCommand updateSQLCmd = new SqlCommand(validateIDSQLString, dbConnection);
SqlDataReader getRecords = updateSQLCmd.ExecuteReader();
try
{
empIDChecker = getRecords["EMP_ID"].ToString();
}
catch
{
empIDChecker = "0";
}
getRecords.Close();
dbConnection.Close();
}
OK, so if your insert sproc looks something like:
sp_InsertEmp
...
INSERT INTO Emp(Name, etc...)
VALUES ('Paul', etc...)
SELECT SCOPE_IDENTITY() AS EMP_ID
GO
And in your code:
SqlCommand insertCmd = new SqlCommand("sp_InsertEmp", dbConnection);
... Add parameters here and set type to StoredProcedure
SqlDataReader dr= insertCmd.ExecuteReader();
int newId;
if (dr.Read())
{
newId = dr.GetInteger(0);
}
you can use
SELECT IDENT_CURRENT(‘tablename’)
This will give you the last inserted auto increment ID of the table, you can use that to insert in other table
Check this link as well http://blog.sqlauthority.com/2007/03/25/sql-server-identity-vs-scope_identity-vs-ident_current-retrieve-last-inserted-identity-of-record/