I have a difficult SQL query, and I don't want to rewrite it on Linq. The problem is: I have two equal tables and I must use one of them in depending on the some condition. So, to pass parameter (the name of table) I use this:
List<Variables> lst = db.Database
.SqlQuery<Variables>(s, new SqlParameter("tableSource", sourceTable))
.ToList();
And My query like this:
SELECT #tableSource.PlanId,
#tableSource.PlanSmall AS PlanImg,
#tableSource.NOb,
...
It Doesn't works, could someone help me, please?
You can't use SqlParameter for this. It is meant to be used to set values for parameters in WHERE clauses for instance. You may consider using a construct like
if (someParam.Equals("thisValue")
{
return "SELECT * FROM thisTable";
} else if (someParam.Equals("thatValue")
{
return "SELECT * FROM thatTable";
}
Related
I am looking for a query validator in C#, which allows me to parse the SQL text from a textbox and verify whether it's correct or not before sending it for execution (MS SQL or DB2 queries).
If you want to validate SQL syntax without the use of a database, the TSql100Parser class will do well for this situation.
Disclaimer, code borrowed from this post here Code to validate SQL Scripts
Pretty straightforward to use though. If it returns null, then there were no errors in parsing it.
using Microsoft.Data.Schema.ScriptDom;
using Microsoft.Data.Schema.ScriptDom.Sql;
public class SqlParser
{
public List<string> Parse(string sql)
{
TSql100Parser parser = new TSql100Parser(false);
IScriptFragment fragment;
IList<ParseError> errors;
fragment = parser.Parse(new StringReader(sql), out errors);
if (errors != null && errors.Count > 0)
{
List<string> errorList = new List<string>();
foreach (var error in errors)
{
errorList.Add(error.Message);
}
return errorList;
}
return null;
}
}
Set your query to sql with this hint:
set PARSEONLY on
It just checks your query and returns, like this:
set PARSEONLY on
select * from tablea
Returns no exception.
While
set PARSEONLY on
select * f rom tablea
returns
Msg 102, Level 15, State 1, Line 2
Incorrect syntax near 'f'.
If you would like to validate/parse just a SELECT statement, regardless of how "heavy-duty" that select statement is, I found out that the best and fastest way to validate a select statement is the following:
- in your code create 2 select statements (strings) such as:
1) Your valid select statement: SELECT * FROM HUGE_TABLE JOIN MULTIPLE_TABLES WHERE <<Condition>>
2) Create a similar select statement such as SELECT TOP 1 * FROM HUGE_TABLE JOIN MULTIPLE_TABLES WHERE <<Condition>>
- Parse/Validate just the second one, regardless of how many joins you have in there, it will parse it in milliseconds, such as:
SqlCommand sqlParse = new SqlCommand(ParseSelectStatement, sqlConn);
try
{
sqlConn.Open();
sqlParse.ExecuteNonQuery()
}
Hope it helps! Cheers!
I think this is what you are looking for. http://www.codeproject.com/KB/database/sqlvalidator.aspx
I am trying to use interceptor to add WITH (NO LOCK) for some queries (not for all queries, so ReadUncommitted is not a choice).
Code looks like this:
var rawSql = sql.ToString();
if (!rawSql.Contains(IQueryOverExtensions.QueryHintNoLockString))
return sql;
var noWhere = rawSql.Substring(0, rawSql.IndexOf(WhereKeyword, StringComparison.InvariantCulture));
var from = noWhere.Substring(noWhere.IndexOf(FromKeyword, StringComparison.InvariantCulture));
var fromWithNoLock = from.Replace("_ ", $"_ {WithNoLock} ");
var sqlWithNoLock = rawSql.Replace(from, fromWithNoLock);
return base.OnPrepareStatement(new SqlString(sqlWithNoLock));
Here, I take part form FROM clause to WHERE clause and to each alias add WITH (NO LOCK)
The issue is, that the final SQL's parameters are all "?" and exception is thrown that SQL is not valid. Why parameters are not filled in and how to fix it?
Thanks in advance
Finally I got it. I had to get number of parameters by calling sql.GetParameterCount() and then replace all question marks with #p0, #p1, #p2, etc.
I've just checked the new futures in Entity Framework Core 2.0. There is a really nice feature in it called "String interpolation in raw SQL methods" which is described here.
It says that this code:
var city = "Redmond";
using (var context = CreateContext())
{
context.Customers.FromSql($#"
SELECT *
FROM Customers
WHERE City = {city}");
}
creates this query:
SELECT *
FROM Customers
WHERE City = #p0
It is really strange to me! How FromSql method is written as it has just and input of type string.
How does it understand it is an interpolated string, and then create a parameter #p0 query for it? How can I write a method like FromSql aware of how its string parameters are created?
The way it woks is FromSql( accepts a FormattableString.
When you use $"..." that returns a FormatableString, that class allows you to inspect the passed in string and see all of the { } blocks inside of and the objects they represent. This allows the framework to replace those { } blocks with a placeholder parameter #p0 then create a new parameter using something similar to new SqlParameter("#p0", formatableString.GetArgument(0))
I have an existing SqlBuilder, which looks like this
var query = SQL
.WHERE("Field1 = {0}", "bob");
Now i want to pass this sqlBuilder into another function, so it can be manipulated, where by a SELECT, FROM and additional WHERE clauses can be added to it, but this doesnt seem to be possible?
If i pass this sqlBuilder into a function and call .SELECT like so
public void myFunction(SqlBuilder sqlBuilder)
{
var newBuilder = sqlBuilder.Clone()
.SELECT("*")
.FROM("myTable")
.WHERE("Field2 = {0}", "something");
}
Now i would expect the SQL to be something like
SELECT * FROM myTable WHERE Field1 = 'bob' AND Field2 = 'something'
But instead i get SQL equal to
WHERE Field1 = 'bob' SELECT * FROM myTable WHERE Field2 = 'something'
Obviously this is invalid. How can i do what i want? Is this not possible with DbExtensions?
As i said, i would like to manipulate the existing SqlBuilder (clone it first) and add additional clauses to it. Do you have to add each clause in order? Thought it would hold each in some sort of background dictionary until it needed to create the SQL string?
With SqlBuilder, order matters, just like with StringBuilder. You have to either adapt your code, or use SqlSet instead.
I am looking for a query validator in C#, which allows me to parse the SQL text from a textbox and verify whether it's correct or not before sending it for execution (MS SQL or DB2 queries).
If you want to validate SQL syntax without the use of a database, the TSql100Parser class will do well for this situation.
Disclaimer, code borrowed from this post here Code to validate SQL Scripts
Pretty straightforward to use though. If it returns null, then there were no errors in parsing it.
using Microsoft.Data.Schema.ScriptDom;
using Microsoft.Data.Schema.ScriptDom.Sql;
public class SqlParser
{
public List<string> Parse(string sql)
{
TSql100Parser parser = new TSql100Parser(false);
IScriptFragment fragment;
IList<ParseError> errors;
fragment = parser.Parse(new StringReader(sql), out errors);
if (errors != null && errors.Count > 0)
{
List<string> errorList = new List<string>();
foreach (var error in errors)
{
errorList.Add(error.Message);
}
return errorList;
}
return null;
}
}
Set your query to sql with this hint:
set PARSEONLY on
It just checks your query and returns, like this:
set PARSEONLY on
select * from tablea
Returns no exception.
While
set PARSEONLY on
select * f rom tablea
returns
Msg 102, Level 15, State 1, Line 2
Incorrect syntax near 'f'.
If you would like to validate/parse just a SELECT statement, regardless of how "heavy-duty" that select statement is, I found out that the best and fastest way to validate a select statement is the following:
- in your code create 2 select statements (strings) such as:
1) Your valid select statement: SELECT * FROM HUGE_TABLE JOIN MULTIPLE_TABLES WHERE <<Condition>>
2) Create a similar select statement such as SELECT TOP 1 * FROM HUGE_TABLE JOIN MULTIPLE_TABLES WHERE <<Condition>>
- Parse/Validate just the second one, regardless of how many joins you have in there, it will parse it in milliseconds, such as:
SqlCommand sqlParse = new SqlCommand(ParseSelectStatement, sqlConn);
try
{
sqlConn.Open();
sqlParse.ExecuteNonQuery()
}
Hope it helps! Cheers!
I think this is what you are looking for. http://www.codeproject.com/KB/database/sqlvalidator.aspx