I am trying to delete entries by ID. I want to notify user that ID they try to delete doesn't exist. It doesn't create any problems, but I want to make everything clear.
How to do that? Do I have to use SQL string to do so?
I am using MS Access 2007 and this is how I delete item:
string SQL = "DELETE FROM PersonalData WHERE DataID = " + txtEntryID.Text;
private void DeleteData(string SQL)
{
// Creating an object allowing me connecting to the database.
// Using parameters in command will avoid attempts of SQL injection.
OleDbConnection objOleDbConnection = new OleDbConnection();
// Creating command object.
objOleDbConnection.ConnectionString =
"Provider=Microsoft.ACE.OLEDB.12.0;" +
"Data Source=" + filePath + ";" +
"Persist Security Info=False;" +
"Jet OLEDB:Database Password=" + pass + ";";
OleDbCommand objOleDbCommand = new OleDbCommand();
objOleDbCommand.CommandText = SQL;
// Assigning a connection string to the command.
objOleDbCommand.Connection = objOleDbConnection;
try
{
// Open database connection.
objOleDbConnection.Open();
objOleDbCommand.ExecuteNonQuery();
}
catch (Exception ex)
{
// Displaying any errors that
// might have occured.
MessageBox.Show("Error: " + ex.Message);
}
finally
{
// Close the database connection.
objOleDbConnection.Close();
}
// Refreshing state of main window.
mainWindow.DisplayFileContent(filePath);
MessageBox.Show("Data was successfully deleted.");
// Clearing text box field.
txtEntryID.Clear();
}
In VBA code, you could use the DCount() function.
You can also just delete the records with a SQL statement and inform the user after the fact; from the user's point of view there's no difference:
Dim id As Long
id = GetAnIdFromTheUser()
With CurrentDb
Do
.Execute "DELETE FROM [TableName] WHERE ID = " & id
If .RecordsAffected > 0 Then
Goto Done
End If
MsgBox "That ID doesn't exist; please try another."
id = GetAnIdFromTheUser()
Loop
Done:
.Close
End With
EDIT:
In ADO.NET you can follow the same approach by examining the return value of ExecuteNonQuery. For example, you could declare your function as bool TryDeleteData(string SQL) and do something like
...
if (objOleDbCommand.ExecuteNonQuery() == 0)
return false;
...
You could use the DCount function of VBA:
DCount("*", "SomeTable", "ID = 1")
If this is 0 then you know the record doesn't exist and can inform the user.
Your question isn't clear enough, so I'm guessing that what you'd like to do is execute the DELETE query and then return whether records were deleted or not. If that's what you want to do you could do it like this:
DECLARE #deletedID AS INT
SELECT #deletedID = id FROM your_table WHERE id = <the id supplied by user>
DELETE FROM your_table
WHERE your_table.id = <the id supplied by user>
RETURN #deletedID
If the requested ID does not exist this will return NULL
EDIT
Based on the clarification in your comments, the following query should work just fine:
SELECT COUNT(DataId) as Cnt
FROM PersonalData WHERE DataId = <user_specified_id>
This query will produce a single column, single row result set (i.e. a scalar-value). The value is going to be either 1 or 0 (assuming only one entry may have the same id). If the count is 0 the entry does not exist.
P.S.
The way you are executing the query you're opening yourself to SQL injection attacks. Basically, someone could give you the following DataID: 0 OR 1 = 1 and guess what's going to happen - all the PersonalData records will be deleted!
A much better approach would be to use prepared statements. Or at the very least, make absolute sure that you sanitize and validate the user input before concatenating it into the query text.
Related
I'm trying to update a Database table and getting the error
"MySql.Data.MySqlClient.MySqlException: 'You have an error in your SQL
syntax; check the manual that corresponds to your MySQL server version
for the right syntax to use near 'group='superadmin' WHERE
identifier='steam:steam:1100001098b5888'' at line 1'"
// Creates query to run
public void UpdateInfo(String jobTitle, int jobGrade, String adminLevel, String identifier) {
// Opens the database connection if it's not already open
if (!(databaseConnected)) {
openConnection();
}
// Creates query to run
String query = "UPDATE " + table + " SET job=#jobTitle, job_grade=#jobGrade, group=#adminLevel WHERE identifier=#identifier";
// Makes a new command
MySqlCommand cmd = new MySqlCommand(query, connection);
// Replaces the # placeholders with actual variables
cmd.Parameters.AddWithValue("#jobTitle", jobTitle);
cmd.Parameters.AddWithValue("#jobGrade", jobGrade);
cmd.Parameters.AddWithValue("#adminLevel", adminLevel);
cmd.Parameters.AddWithValue("#identifier", identifier);
// Executes it and if it's...
if (cmd.ExecuteNonQuery() > 0) {
// Successful
MessageBox.Show("Successfully updated information");
closeConnection();
return;
} else {
// Not successful
MessageBox.Show("Error with updating information!");
// Closes the connection again to prevent leaks
closeConnection();
return;
}
}
I tried your query on https://sqltest.net/ and noticed it highlighted "group" when I tried to create the table. I'm wondering if the problem might be the usage of "group" as a column name since it's a reserved word.
Is it possible to try renaming the column to group_level or adding back ticks around 'group' or "group" and seeing if that works?
So for example
'group'=#grouplevel
I found this thread and this thread on renaming the column where they had issues with "group" as a column name. Adding backticks seemed to solve both problems.
EDIT: As per OP, double quotes (") solved the issue instead of single. Edited answer to include.
Try change query like this
String query = "UPDATE " + table + " SET job='#jobTitle', job_grade=#jobGrade, group='#adminLevel' WHERE identifier='#identifier'";
if you input String value with query, you need to use 'this' for work
I hope this will work for you.
if not, you can use String.Format for that like this.
String Query = String.Format("Update `{0}` Set job='{1}', job_grade={2}, group='{3}' Where identifier='{4}'", table, jobTitle, jobGrade, adminLevel, identifier);
I tried to search a lot for tutorials on Npgsql and c#. but I couldn't resolve the below problem.
When I run the program, my programs stop and breaks at execute query. and when I try debug and check the return value from the execute reader is empty.
below is the sample code:
string user=textBox1.Text;
NpgsqlConnection dataconnect = new NpgsqlConnection(
"Server=127.0.0.1;Port=5432;User Id=dbuser;Password=dbpass;Database=dbname;");
string query = "Select USERNAME from helperdata.credentials where USERNAME = "
+ textBox1.Text + " and PASSWORD = " + textBox2.Text;
dataconnect.Open();
NpgsqlCommand command = new NpgsqlCommand(query, dataconnect);
NpgsqlDataReader reader = command.ExecuteReader();
if(reader.Read())
{
MessageBox.Show("Login Successful");
}
else
{
MessageBox.Show("Login failed");
}
reader.Close();
dataconnect.Close();
When I try to run the below query in Pgsql it returns the data.
Select "USERNAME" from helperdata.credentials where "USERNAME" = 'admin'
I am new to Npgsql.
I would also like if someone could provide me some good tutorial sites which provides detail explanation of Npgsql and C#.
Thanks in advance.
I have identified two problems in your code. The first the usage of uppercase letters on PostgreSQL identifiers. PostgreSQL allows identifiers with other than simple lowercase letter, but only if you quote them.
In fact, you can use, for instance:
CREATE TABLE helperdata.credentials (... USERNAME varchar, ...);
But PostgreSQL will convert it to:
CREATE TABLE helperdata.credentials (... username varchar, ...);
So, to make it really left with uppercase, you have to quote it as following:
CREATE TABLE helperdata.credentials (... "USERNAME" varchar, ...);
And that seems to be the way you have created your table, and the problem with that is that always you refers to that table in a query, you'll have to quote it. So the beginning of your query should be:
string query = "Select \"USERNAME\" from helperdata.credentials ... ";
My recommendation, is to modify your column and table names to don't use such identifiers. For this case you can do:
ALTER TABLE helperdata.credentials RENAME COLUMN "USERNAME" TO username;
The second problem, is the lack of string quotation when you concatenated the username from the textbox into the query. So, you should do something as the following (BAD PRACTICE):
string query = "Select \"USERNAME\" from helperdata.credentials where \"USERNAME\" = '"
+ textBox1.Text + "' and \"PASSWORD\" = '" + textBox2.Text + "'";
There is a huge problem with that, you can have SQL injection. You could create a function (or use one from Npgsql, not sure if there is) to escape the string, or, more appropriately, you should use a function that accept parameters in the query using NpgsqlCommand, which you can simple send the parameters or a use a prepared statement.
Check the Npgsql documentation, and find for "Using parameters in a query" and "Using prepared statements" to see examples (there are no anchors in the HTML to link here, so you'll have to search).
Maybe this is not the best source I've ever written but it is for a simple form that has the goal to write data remotely.
I've two MySQLConnections both for a local database. localconnection is used to read the DB and updateconnection edit every single row. The problem is that when i'm trying to update the Database the program raise a timeout and it crash.
I think the problem is generated by the while loop.
My intention is to read a single row, post it on the server and update it if the server returns the status equals 200.
Here's the code, it fails on updateConnection.ExcecuteNonQuery();
// Local Database here.
localCommand.Parameters.Clear();
// 0 - Grab unsent emails
string receivedMessages = "SELECT * FROM EMAIL WHERE HASSENT = 0";
// Update connection init START
string updateConnectionString = "Server=" + this.localServer + ";Database=" + this.localDatabase + ";Uid=" + this.localUser + ";Pwd=" + this.localpassword;
MySqlConnection updateConnection = new MySqlConnection(updateConnectionString);
updateConnection.Open();
MySqlTransaction transaction = updateConnection.BeginTransaction();
MySqlCommand updateCommand = new MySqlCommand();
// Update connection init END
localCommand.Connection = localConnection;
localCommand.Prepare();
try
{
localCommand.CommandText = receivedMessages;
MySqlDataReader reader = localCommand.ExecuteReader();
while (reader.Read()) // Local db read
{
String EID = reader.GetString(0);
String message = reader.GetString(3);
String fromEmail = reader.GetString(6);
String toEmail= reader.GetString(12);
// 1 - Post Request via HttpWebRequest
var receivedResponse = JObject.Parse(toSend.setIsReceived(fromEmail, message, toEmail));
// 2 - Read the JSON response from the server
if ((int)receivedResponse["status"] == 200)
{
string updateInbox = "UPDATE EMAIL SET HASSENT = 1 WHERE EMAILID = #EID";
MySqlParameter EMAILID = new MySqlParameter("#EID", MySqlDbType.String);
EMAILID.Value = EID; // We use the same fetched above
updateCommand.Connection = updateConnection;
updateCommand.Parameters.Add(IID_value);
updateCommand.Prepare();
updateCommand.CommandText = updateInbox;
updateCommand.ExecuteNonQuery();
}
else
{
// Notice the error....
}
}
}
catch (MySqlException ex)
{
transaction.Rollback();
// Notice...
}
finally
{
updateConnection.Close();
}
It is hard to tell exactly what's wrong here without doing some experiments.
There are two possibilities, though.
First, your program appears to be running on a web server, which necessarily constrains it to run for a limited amount of time. But, you loop through a possibly large result set, and do stuff of an uncontrollable duration for each item in that result set.
Second, you read a result set row by row from the MySQL server, and with a different connection try to update the tables behind that result set. This may cause a deadlock, in which the MySQL server blocks one of your update queries until the select query completes, thus preventing the completion of the select query.
How to cure this? First of all, try to handle a fixed and small number of rows in each invocation of this code. Change your select query to
SELECT * FROM EMAIL WHERE HASSENT = 0 LIMIT 10
and you'll handle ten records each time through.
Second, read in the whole result set from the select query, into a data structure, then loop over the items. In other words, don't nest the updates in the select.
Third, reduce the amount of data you handle by changing SELECT * to SELECT field, field, field.
I am writing a small program using an SQL database. The table name is StudentInfo.
I need to know the SQL code for the following
for (n=0; n<nRows; n++) {
string sql1="update StudentInfo set Position=" + n + " where <this has to be the row number>";
}
nRows is number of rows.
How can I get the row number for the above code?
best way to do this is to create a stored procedure in the database and use your code to pass the relevent information to the server
In order to accomplish this task you'll want to create a Stored Procedure or build a Query that actually accepts parameters. This will help you pass variables between, your method of concatenation will actually cause an error or become susceptible to SQL Injection attacks.
Non Parameter SQL Command:
using(SqlConnection sqlConnection = new SqlConnection("Database Connection String Here"))
{
string command =
"UPDATE Production.Product " +
"SET ListPrice = ListPrice * 2 " +
"WHERE ProductID IN " +
"(SELECT ProductID " +
"FROM Purchasing.ProductVendor" +
"WHERE BusinessEntityID = 1540);" +
using (SqlCommand sqlCommand = new SqlCommand(command, sqlConnection))
{
int execute = command.ExecuteNonQuery();
if( execute <= 0)
{
return false;
}
else
{
return true;
}
}
}
That method is essentially creation a connection, running our SQL Command, then we are using an integer to verify that it did indeed run our command successful. As you can see we simply using SQL to run our command.
The other important thing to note, you can't create a sub-query with an update; you have to create an update then run a select as the sub-query to hone in more specific data across so you can span across tables and so on.
The other alternative would be to use a parameter based query, where your passing variables between SQL and your Application.
I won't post code to that, because I believe you wrote the C# loop to demonstrate what you would like SQL to do for you. Which is only update particular rows; based on a specific criteria.
If you could post additional information I'd be more then happy to help you. But I'm just going to post what I believe you are trying to accomplish. Correct me if I'm wrong.
I want to read data from a table whose name is supplied by a user. So before actually starting to read data, I want to check if the database exists or not.
I have seen several pieces of code on the NET which claim to do this. However, they all seem to be work only for SQL server, or for mysql, or some other implementation. Is there not a generic way to do this?
(I am already seperately checking if I can connect to the supplied database, so I'm fairly certain that a connection can be opened to the database.)
You cannot do this in a cross-database way. Generally DDL (that is, the code for creating tables, indexes and so on) is completely different from database to database and so the logic for checking whether tables exist is also different.
I would say the simplest answer, though, would simply be something like:
SELECT * FROM <table> WHERE 1 = 0
If that query gives an error, then the table doesn't exist. If it works (though it'll return 0 rows) then the table exists.
Be very careful with what you let the user input, though. What's to stop him from from specifying "sysusers" as the table name (in SQL Server, that'll be the list of all database users)
You can use the DbConnection.GetSchema family of methods to retreive metadata about the database. It will return a DataTable with schema objects. The exact object types and restriction values may vary from vendor to vendor, but I'm sure you can set up your check for a specific table in a way that will work in most databases.
Here's an example of using GetSchema that will print the name and owner of every table that is owned by "schema name" and called "table name". This is tested against oracle.
static void Main(string[] args)
{
string providerName = #"System.Data.OracleClient";
string connectionString = #"...";
DbProviderFactory factory = DbProviderFactories.GetFactory(providerName);
using (DbConnection connection = factory.CreateConnection())
{
connection.ConnectionString = connectionString;
connection.Open();
DataTable schemaDataTable = connection.GetSchema("Tables", new string[] { "schema name", "table name" });
foreach (DataColumn column in schemaDataTable.Columns)
{
Console.Write(column.ColumnName + "\t");
}
Console.WriteLine();
foreach (DataRow row in schemaDataTable.Rows)
{
foreach (object value in row.ItemArray)
{
Console.Write(value.ToString() + "\t");
}
Console.WriteLine();
}
}
}
That's like asking "is there a generic way to get related data" in databases. The answer is of course no - the only "generic way" is to have a data layer that hides the implementation details of your particular data source and queries it appropriately.
If you are really supporting and accessing many different types of databases without a Stategy design pattern or similar approach I would be quite surprised.
That being said, the best approach is something like this bit of code:
bool exists;
try
{
// ANSI SQL way. Works in PostgreSQL, MSSQL, MySQL.
var cmd = new OdbcCommand(
"select case when exists((select * from information_schema.tables where table_name = '" + tableName + "')) then 1 else 0 end");
exists = (int)cmd.ExecuteScalar() == 1;
}
catch
{
try
{
// Other RDBMS. Graceful degradation
exists = true;
var cmdOthers = new OdbcCommand("select 1 from " + tableName + " where 1 = 0");
cmdOthers.ExecuteNonQuery();
}
catch
{
exists = false;
}
}
Source: Check if a SQL table exists
You can do something like this:
string strCheck = "SHOW TABLES LIKE \'tableName\'";
cmd = new MySqlCommand(strCheck, connection);
if (connection.State == ConnectionState.Closed)
{
connection.Open();
}
cmd.Prepare();
var reader = cmd.ExecuteReader();
if (reader.HasRows)
{
Console.WriteLine("Table Exist!");
}
else (reader.HasRows)
{
Console.WriteLine("Table Exist!");
}