I have a requirement where I have to replace the database names in the dynamic sql with the new database names .
something like following:
select * from DBName.TableName
should become
select * from newDBName.TableName
select * from [DbName].TableName
should become
select * from [NewDbName].TableName
I have tried string.Replace() method but that doesn't respect all combinations a programmer can write the database names in a dynamic sql
Please help.
Instead of trying to replace parts of a string, you should use a formatted string and pass in the parameter. For example:
var query = String.Format("select * from {0}.TableName", newDB)
used in a method where you can pass in the new db name and return the new query.
public static string GetNewQuery(string newDB) {
return String.Format("select * from [{0}].TableName", newDB);
}
would result in "select * from [newDB].TableName"
https://msdn.microsoft.com/en-us/library/system.string.format(v=vs.110).aspx
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"),
});
}
So I have this query:
var retval = db.v_AViewOfJoinedTables.SqlQuery("SELECT * FROM dbo.v_AViewOfJoinedTables WHERE #filter = '#value';",
new SqlParameter("#filter", columnname),
new SqlParameter("#value", value)).ToList();
But I'm not getting any result. If I run this query through SSMS, it returns data. I know if I use a table instead that it works. So can SqlQuery only work on tables or is something wrong my query or code?
UPDATED CODE:
SqlCommandBuilder scb = new SqlCommandBuilder();
string columnname = userNameFilterType;
string escapedColumnName = scb.QuoteIdentifier(columnname);
string sqlQuery = String.Format("SELECT * FROM dbo.v_AViewOfJoinedTables WHERE {0} = '#username';", escapedColumnName);
var retval = db.v_AViewOfJoinedTables.SqlQuery(sqlQuery, new SqlParameter("username", currentUser)).ToList();
return retval.AsQueryable();
The problem isn't the view. You can't use SQL parameters for table or column names.
... where #filter = ...
That won't work. It must be text. Just use string interpolation to insert it:
var retval = db.v_AViewOfJoinedTables.SqlQuery($"SELECT * FROM dbo.v_AViewOfJoinedTables WHERE {columnname} = #value;",
new SqlParameter("#value", value)).ToList();
The SQL Execution Engine will cache the execution plan of queries you run, but it can't do that if the query itself changes. The plan might change depending on the column name, for instance. So, SQL parameters will only ever work as values supplied to the query.
You also need to remove the single quotes around #value. The SQL Server provider will handle the quote insertion for you.
I'm running the following query
cmd = new SqlCommand("SELECT * FROM addresses WHERE identifier NOT IN(#notIn)", _connector.getMsConnection());
When I view the value notIn and copy this query I get an empty result on my database (which I'm expecting). However when I'm running this code I get 6 results. The content of string notIN is for example
string notIn = "'201619011124027899693E8M2S3WOCKT9G6KHE11' ,'201619011124027899693E8M2S3WOCKT9G6KHE12'"
which combined with
SELECT *
FROM addresses
WHERE identifier NOT IN(#notIn)
Should create
SELECT *
FROM addresses
WHERE identifier NOT IN ('201619011124027899693E8M2S3WOCKT9G6KHE11',
'201619011124027899693E8M2S3WOCKT9G6KHE12' )
which runs as expected.
it should be like this:
cmd = new SqlCommand(string.Format("SELECT * FROM addresses WHERE identifier NOT IN({0})", notIn), _connector.getMsConnection());
This way the value of notIn will be concat to your string query.
Contrary to what the other answers say, concatenating the string to build the SQL is a bad idea, especially since the input values are strings. You open yourself up to SQL injection attacks.
You should be generating multiple parameters for each item in your list.
For example, if you have the input input:
var notIn = new[] { "A1", "B2", "C3" }
You'd want something like
for(var i = 0; i < notIn.Length; i++)
command.AddParamWithValue("p"+i, notIn);
And then you can build the SQL with concatenation (note that we are not concatenating an input here)
var sql = "SELECT * FROM addresses WHERE identifier NOT IN(" + string.Join(",", notIn.Select(i,v) => { "#p" + i; }) + ")";
Which then would look like:
SELECT * FROM addresses WHERE identifier NOT IN (#p0,#p1,#p2)
Alternatively, you could dump the values into a temporary table and do a join.
Note that the above is pseudocode, and may not compile verbatim, but should give you the right idea about how to procede.
It's because, you passed the #notIn as a whole string, which means, the SQL server see it as:
SELECT * FROM addresses WHERE identifier NOT IN('''201619011124027899693E8M2S3WOCKT9G6KHE11'',''201619011124027899693E8M2S3WOCKT9G6KHE12''')
So you got empty result
Try changing the "not in" to where clause and generate the where with C#:
string selectStatement = "SELECT * FROM addresses WHERE";
selectStatement += " identifier != '201619011124027899693E8M2S3WOCKT9G6KHE11' and identifier != '201619011124027899693E8M2S3WOCKT9G6KHE12'";
Or if you really want to use parameterized SQL, try doing it in stored procedure instead.
I'm trying to parameterize a raw SQL query for an Oracle synonym (non-entity) in EF 4 and I am having some problems. Currently I am doing something like the code below, based on some examples that I saw:
string term="foo";
OracleParameter p = new OracleParameter("#param1", term);
object[] parameters = new object[] { p };
var model = db.Database.SqlQuery<ProjectTask>("SELECT * FROM (SELECT * FROM web_project_task_vw WHERE project_num like '%#param1%') WHERE rownum<=100", parameters).ToList();
Running this doesn't return any results. If I replace the parameter with something like
"SELECT * FROM web_project_task_vw WHERE project_num like '%"+term+"%'"
it returns the results I expect, but this is obviously a SQL injection risk.
Can anyone point me in the right direction for how parameters are supposed to work in EF 4 for an Oracle DB?
Thanks.
First, like Mohammed wrote, you need to prefix the parameter with ':', but not as you define it, just in the query.
Second, you are currently searching not for the value of the parameter but rather strings that contains the string #param1. So surround the value of the parameter with % and you should get a result.
So it should look something like this:
string term="foo";
OracleParameter p = new OracleParameter("param1", term);
object[] parameters = new object[] { p };
var model = db.Database.SqlQuery<ProjectTask>("SELECT * FROM (SELECT * FROM web_project_task_vw WHERE project_num like '%'||:param1||'%') WHERE rownum<=100", parameters).ToList();
Your p might have an incorrect parameter name; the name should be param1, not #param1. Your query is also incorrect; replace '%#param1%' with '%:param1%'.
How to write a select statement with where clause.i need to compare with a string value.
I tried this:
string get_dropdown_value = dropdown_category.SelectedItem.Value;
...but it gives me this error:
Invalid column name 'get_dropdown_value'.
You will have to show the select statement you are using. I suspect you have done something like this:
string selectStatement = "SELECT * FROM SOME_TABLE WHERE SOME_COLUMN = get_dropdown_value";
While it should be like:
string selectStatement = "SELECT * FROM SOME_TABLE WHERE SOME_COLUMN = " + get_dropdown_value;
Edit: As others mentioned, this is prone to SQL Injection. So, you might want to use SqlParamter (assuming you are using SQL).
Try this code
insted of
string get_dropdown_value = dropdown_category.SelectedItem.Value;
Put
string get_dropdown_value = dropdown_category.SelectedItem.Text;