I know a lot of questions exists about this topic. But i tried everything and nothing worked. As I mentioned in the title, i'm trying to change my unsafe query into a safer one.
I think the problem are the points. My goal is to insert the month and the year into the query. And both should be separated by points.
Just something like this: " .08.2017 "
The old query which worked
string Query = #"select id from ferien WHERE Datum LIKE '%." + monat + "." + jahr + "'";
The new query which doesn't work
String Query = #"select id from ferien WHERE Datum LIKE '%. #monat . #jahr'";
using (SQLiteCommand command = new SQLiteCommand(Query, sqlite_conn))
{
command.Parameters.Add("#monat", monat);
command.Parameters.Add("#jahr", jahr);
command.ExecuteNonQuery();
}
I'm using a sqlite db.
I'm thankful for any advice or solution.
Edit
It doesn't give me any errors. While debugging it runs trough like normal. It just acts like it found nothing in the db.
Fixing your current approach:
You'd have to concat the parameter with the fixed part of the query, so depending on your database, it would be something like
select id from ferien WHERE Datum LIKE '%.' || #monat || '.' || #jahr
or
select id from ferien WHERE Datum LIKE CONCAT('%.', #monat, '.', #jahr)
I think the first one using the common || SQL concatenation operator works in SQLite as well. Note that the common + operator typically doesn't work for string concatenation in SQL.
The whole code would become
String Query = #"select id from ferien WHERE Datum LIKE '%' || #monat || '.' || #jahr";
using (SQLiteCommand command = new SQLiteCommand(Query, sqlite_conn))
{
command.Parameters.Add("#monat", monat);
command.Parameters.Add("#jahr", jahr);
command.ExecuteNonQuery();
}
(Better?) between:
That aside, it would be even better if you have an actual date in your database, and you would use that in your query, so it would look like:
select id from ferien WHERE Datum BETWEEN "2017-08-01" AND "2017-09-01"
See also SQLite: SQL Select between dates
You're not using the parameters in the right way, they have to be a single value and cannot be used as string replacements (like you're doing). So use this instead
String Query = #"select id from ferien WHERE Datum LIKE #date";
using (SQLiteCommand command = new SQLiteCommand(Query, sqlite_conn))
{
command.Parameters.Add("#date", $".{monat}.{jahr}");
command.ExecuteNonQuery();
}
Related
I have a table with a lot of employees in it, every person has a Name column with their full name.
I then want to do a query similar to this when searching for people:
SELECT * FROM Employees WHERE Name LIKE '%' + #value1 + '%' AND Name LIKE '%' + #value2 +'%' AND so forth...
for an arbitrary array of values.
My Dapper code would look something like this:
public IEnumerable<Employee> Search(string[] words)
{
using var connection = CreateConnection();
connection.Query<Employee>("SELECT * etc.", words);
}
Is there ANY way to do this with SQL without resorting to string concatenation, and the risk of SQL Injection attacks that follows?
Caveat: I don't know how Dapper actually passes an array to the query, which limits my creative ideas for working around this :-D
And also: Changing the Table structure is, unfortunately, out of the question. And I'd rather avoid fetching every single person into .Net memory and doing the filtering there.
Is there ANY way to do this with SQL without resorting to string concatenation, and the risk of SQL Injection attacks that follows?
Because the set of where conditions is not fixed you will need to build the query dynamically. But that does not mean you cannot parameterise the query, you just build the parameter list alongside building the query. Each time a word from the list add to the condition and add a parameter.
As Dapper doesn't directly include anything that takes a collection of DbParameter, consider using ADO.NET to get an IDataReader and then Dappter's
IEnumerable<T> Parse<T>(this IDataReader reader)
for the mapping.
Such a builder would be very roughly
var n = 0;
for (criterion in cirteria) {
var cond = $"{crition.column} like #p{n}";
var p = new SqlPatameter($"#p{n}", $"%{crition.value}%";
conditions.Add(cond);
cmd.Parameters.Add(p);
}
var sql = "select whetever from table where " + String.Join(" and ", conditions);
cmd.CommandText = sql;
var reader = await cmd.ExecuteReaderAsync();
var res = reader.Parse<TResult>();
For performance reasons, it's much better to do this as a set-based operation.
You can pass through a datatable as a Table-Value Parameter, then join on that with LIKE as the condition. In this case you want all values to match, so you need a little bit of relational division.
First create your table type:
CREATE TYPE dbo.StringList AS TABLE (str varchar(100) NOT NULL);
Your SQL is as follows:
SELECT *
FROM Employees e
WHERE NOT EXISTS (SELECT 1
FROM #words w
WHERE e.Name NOT LIKE '%' + w.str + '%' ESCAPE '/' -- if you want to escape wildcards you need to add ESCAPE
);
Then you pass through the list as follows:
public IEnumerable<Employee> Search(string[] words)
{
var table = new DataTable{ Columns = {
{"str", typeof(string)},
} };
foreach (var word in words)
table.Rows.Add(SqlLikeEscape(word)); // make a function that escapes wildcards
using var connection = CreateConnection();
return connection.Query<Employee>(yourQueryHere, new
{
words = table.AsTableValuedParameter("dbo.StringList"),
});
}
Note: I am aware that this question has been asked before, and I am sorry for such a dumb re-post. However, none of the solutions that I've found actually helped me. I might have looked in the wrong place - excuse me for that!
Right, so I am trying to add a new entry in the Releases table in my database. The following shows how my code looks like.
[HttpPost]
public IActionResult Create(Release release)
{
var userId = this.User.FindFirstValue(ClaimTypes.NameIdentifier);
string connectionString = Configuration["ConnectionStrings:DefaultConnection"];
using (SqlConnection connection = new SqlConnection(connectionString))
{
string sql = $"Insert Into Releases (Id, Name, StartDate, EndDate, OwnerId) Values ('(SELECT MAX(Id) + 1 FROM dbo.Releases)', '{release.Name}','{release.StartDate}','{release.EndDate}','{userId}')";
using (SqlCommand command = new SqlCommand(sql, connection))
{
command.CommandType = CommandType.Text;
connection.Open();
command.ExecuteNonQuery();
connection.Close();
}
}
return View();
}
In my code snippet, I use SELECT MAX(Id) + 1 in order to insert the new entry with the value of column Id + 1 the latest entry. This has worked before for me, but now, for some reason, I am getting the following error:
System.Data.SqlClient.SqlException: 'Conversion failed when converting the varchar value '(SELECT MAX(Id) + 1 FROM dbo.Releases)' to data type int.'
While this solution might not be quite ideal - I am looking for a proper solution to my problem.
In answer to your question '(SELECT MAX(Id) + 1 FROM dbo.Releases)' should not be enclosed in quotes; (SELECT MAX(Id) + 1 FROM dbo.Releases) would return an integer value that is required by your id column.
However, you should really be using an auto-increment column for your id, as simultaneous requests could try to insert the same id twice.
You should also be using parameterised queries rather than string interpolation, as this is opening up your database to SQL injection.
This question already has answers here:
SqlCommand with Parameters
(3 answers)
Closed 8 years ago.
Hi this is my query
SELECT StraightDist FROM StraightLineDistances
WHERE (FirstCity='007' AND SecondCity='017');
How can I pass this in to sql statement?
I want to replace the city numbers '007' and '017' with variables
string destcity;
string tempcityholder1;
What I tried is this
SqlCommand mybtncmd2 = new SqlCommand("SELECT StraightDist FROM StraightLineDistances WHERE (FirstCity='" + tempcityholder1 + "' AND SecondCity='" + destcity + "');", mybtnconn2);
it didn't give me the expected output.
But when i tried with the original sql as given below it worked.
SqlCommand mybtncmd2 = new SqlCommand("SELECT StraightDist FROM StraightLineDistances WHERE (FirstCity='007' AND SecondCity='017');", mybtnconn2);
Can anyone point me the error here?
or a better solution.
This is for a personal application, security is not a must, so no need of parametrized queries. And I don't know how to implement parametrized queries with multiple parameters. If anyone can explain how to use a parametrized query it's great and I would really appreciate that. But just for the time being I need to correct this.
Any help would be great..
OK if with parametrized query
MY Work looks like this
SqlConnection mybtnconn2 = null;
SqlDataReader mybtnreader2 = null;
mybtnconn2 = new SqlConnection("");
mybtnconn2.Open();
SqlCommand mybtncmd2 = new SqlCommand("SELECT StraightDist FROM StraightLineDistances WHERE (FirstCity='007' AND SecondCity='017');", mybtnconn2);
mybtnreader2 = mybtncmd2.ExecuteReader();
while (mybtnreader2.Read())
{
MessageBox.Show(mybtnreader2.GetValue(0) + "My btn readre 2 value");
}
Can anyone give me a solution which doesn't complicate this structure.
If I use a parametrized query how can I edit
mybtnreader2 = mybtncmd2.ExecuteReader();
This statement?
This is the way to use parametrized queries:
string sqlQuery="SELECT StraightDist FROM StraightLineDistances WHERE (FirstCity= #tempcityholder1 AND SecondCity=#destcity);"
SqlCommand mybtncmd2 = new SqlCommand(sqlQuery, mybtnconn2);
mybtncmd2.Parameters.AddWithValue("tempcityholder1", tempcityholder1 );
mybtncmd2.Parameters.AddWithValue("destcity", destcity);
It's always good practice to use parameters, for both speed and security. A slight change to the code is all you need:
var mybtncmd2 = new SqlCommand("SELECT StraightDist FROM StraightLineDistances WHERE FirstCity=#City1 AND SecondCity=#City2;", mybtnconn2);
mybtncmd2.Parameters.AddWithValue("#City1", "007");
mybtncmd2.Parameters.AddWithValue("#City2", "017");
Use prepared statements: it's both easy and secure.
command.CommandText =
"INSERT INTO Region (RegionID, RegionDescription) " +
"VALUES (#id, #desc)";
SqlParameter idParam = new SqlParameter("#id", SqlDbType.Int, 0);
SqlParameter descParam =
new SqlParameter("#desc", SqlDbType.Text, 100);
You really won't do this, because this is an open door to SQL injection.
Instead you should use Stored Procedures for that approach.
In case your not familiar with SQL injection, let's make it clear:
Assume that you have a database with a table called 'T_USER' with 10 records in it.
A user object has an Id, a Name and a Firstname.
Now, let's write a query that select a user based on it's name.
SELECT * FROM T_USER WHERE Name= 'Name 1'
If we take that value from C#, this can really take unexpected behaviour.
So, in C# code we will have a query:
string queryVal;
var command = "SELECT * FROM T_USER WHERE Name = '" + queryVal + "'";
As long as the user is nice to your application, there's not a problem.
But there's an easy way to retrieve all records in this table.
If our user passes the following string in QueryVal:
demo' OR 'a' = 'a
Then our query would become:
SELECT * FROM T_USER WHERE Name = 'demo' OR 'a' = 'a'
Since the second condition is always true, all the records are retrieved from this table.
But we can even go further:
If the same user uses the following value in queryVal:
demo'; DELETE FROM T_USER--
The full query becomes:
SELECT * FROM T_USER WHERE Name = 'demo'; DELETE FROM T_USER--'
And all our records our gone.
And we can even go further by dropping the table:
queryVal needs to be:
demo'; DROP TABLE T_USER--
I think you get it. For more information google on Sql Injection:
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).
I'm having troubles trying to execute a SQL query with repeated parameters using entity framework.
The query is a keyword search, that looks in different tables, therefore using the same parameter many times. I'm using LIKE statements (yes, I know I should be using FULLTEXTSEARCH, but I don't have time for that right now).
I've tried all the syntax explained here: How to use DbContext.Database.SqlQuery<TElement>(sql, params) with stored procedure? EF Code First CTP5 and none of them make the query work (I get zero returned rows).
I even tried building a string array in runtime, with length equal to the number of times the parameter repeats in the query, and then populating all the elements of the array with the keyword search term. Then I passed that as the object[] parameters. Didn't work either.
The only thing that works is to make a search&replace that is obviously a bad idea because the parameter comes from a text input, and I'll be vulnerable to SQL injection attacks.
The working code (vulnerable to SQL injection attacks, but the query returns rows):
//not the real query, but just for you to have an idea
string query =
"SELECT Field1, " +
" Field2 " +
"FROM Table1 " +
"WHERE UPPER(Field1) LIKE '%{0}%' " +
"OR UPPER(Field2) LIKE '%{0}%'";
//keywordSearchTerms is NOT sanitized
query = query.Replace("{0}", keywordSearchTerms.ToUpper());
List<ProjectViewModel> list = null;
using (var context = new MyContext())
{
list = context.Database.SqlQuery<ProjectViewModel>(query, new object[] { }).ToList();
}
return list;
I'm using ASP.NET MVC 4, .NET 4.5, SQL Server 2008 and Entity Framework 5.
Any thoughts on how to make the SQLQuery<> method populate all the occurrences of the parameter in the query string? Thank you very much for your time.
Try this:
string query =
#"SELECT Field1,
Field2
FROM Table1
WHERE UPPER(Field1) LIKE '%' + #searchTerm + '%'
OR UPPER(Field2) LIKE '%' + #searchTerm + '%'";
context.SqlQuery<ProjectViewModel>(query, new SqlParameter("#searchTerm", searchTerm)).ToList();
You can use parameters in your query. Something like this
string query =
"SELECT Field1, " +
" Field2 " +
"FROM Table1 " +
"WHERE UPPER(Field1) LIKE #searchTerm" +
"OR UPPER(Field2) LIKE #searchTerm";
string search= string.Format("%{0}%", keywordSearchTerms);
context.SqlQuery<ProjectViewModel>(query, new SqlParameter("#searchTerm", search)).ToList();
how about try this
string query =
string.Format("SELECT Field1, Field2 FROM Table1 WHERE UPPER(Field1) LIKE '%{0}%'
OR UPPER(Field2) LIKE '%{0}%'",keywordSearchTerms.ToUpper());
context. Database.SqlQuery< ProjectViewModel >(query)