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
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 try to query a SQL server using Dapper and get it to return a list of class objects with the column values as the matching properties for each object. I have a class called LeaveInfo with the following properties:
ID, Name, Date_, Leave, TDY, Appointments, Unavailable
and a SQL Table with matching columns, except Name. My code for the query is:
public List<LeaveInfo> getLeaveInfo(string id, string date)
{
using (IDbConnection connection = new System.Data.SqlClient.SqlConnection(Helper.ConnectStr("Schedules")))
{
return connection.Query<LeaveInfo>("dbo.LeaveCalendar_GetLeave #ID, #Date_",
new { ID = id, Date_ = date }).ToList();
//return connection.Query<Person>("dbo.Personnel_GetShift #Shift_", new { Shift_ = shift_ }).ToList();
//return connection.Query<Truck>("dbo.Trucks_GetTrucks").ToList();
}
}
SQL Procedure being called:
Create Procedure LeaveCalendar_GetLeave
#ID VARCHAR(2),
#Date_ Date
As
Begin
Set NoCount on
Select * from LeaveCalendar
Where ID = #ID and Date_ = #Date_
End
Instead of returning all of the columns it only returns ID and Date_.
The commented out code are two similar queries that do the same thing and work exactly right, returning all property values of their respective classes.
I have queried it manually in SQL server
Select * from LeaveCalendar
Where ID = 54 and Date_ = '20191011'
for instance..
and it works fine there. So I have two other queries that work and as far as I can tell no errors with the SQL portion. I am not sure where the disconnect is occurring at this point.
I checked the property names to make sure they are aligning with the column names. Not only do they, but I have two procedures to add and delete information, to the same table using the same values, that also work.
So I can add and delete information just not check it from within the application...
Edit:
Apologies for the late additions and thank you for the time you all took to help. Unfortunately I found a syntax error elsewhere that resolved my issues, it's a wonder what fresh eyes will do for you...
It doesn't seem I can delete my question despite the trivial root cause.
public List<LeaveInfo> getLeaveInfo(string id, string date)
{
using (IDbConnection connection = new System.Data.SqlClient.SqlConnection(Helper.ConnectStr("Schedules")))
{
var param = new DynamicParameters();
param.Add("#ID", id, DbType.String, ParameterDirection.Input);
param.Add("#Date_", date, DbType.String, ParameterDirection.Input);
return connection.Query<LeaveInfo>("dbo.LeaveCalendar_GetLeave", param, commandType: CommandType.StoredProcedure).ToList();
//return connection.Query<Person>("dbo.Personnel_GetShift #Shift_", new { Shift_ = shift_ }).ToList();
//return connection.Query<Truck>("dbo.Trucks_GetTrucks").ToList();
}
}
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";
}
My access database had 700 records,every record had 50 fields。I use ODBC Query of PHP which query speed is very fast,but i use ODBC Query of C# ,it speed is very slowly,codes below:
m_conn = new OdbcConnection("DSN=real");//This DSN set by through the windows control panel,ODBC manager,system dsn
m_conn.Open();
string sqlstr="select * from table1 where id = 1";
OdbcCommand selectCMD = new OdbcCommand(sqlstr, m_conn);
OdbcDataReader myreader;
myreader = selectCMD.ExecuteReader();
if (myreader == null)
return null;
string s =myreader["field"].ToString();//here,execution speed is very slow,why?
thanks for help
Don't select more data for your application than you need to process.
Your statement select * from table1 where id = 1 is selecting all fields. If you only need the field named field, than change your select statement to select field from table1 where id = 1.
If you provide additional information on your database structure I may be able to be of more help.
There are a couple of suggestions here. I am guessing that you are accessing this code multiple times, which is where the slowness is coming in. This is most likely caused by you not disposing/closing of the connections properly. Below is the code refactored with the using clause, which enforces the use of Dispose after the call.
Also, instead of using the asterisk, specifying the name of the columns will help access optimize the query.
Finally, if you are only concerned about 1 variable, consider changing the query to only return the one value you are looking for and changing the call to an ExecuteScalar() call.
// Consider specifying the fields you are concerned with
string sqlstr="select * from table1 where id = 1";
using (var m_conn = new OdbcConnection("DSN=real"))//This DSN set by through the windows control panel,ODBC manager,system dsn
using (var selectCMD = new OdbcCommand(sqlstr, m_conn))
{
m_conn.Open();
using (var myreader= selectCMD.ExecuteReader())
{
if (myreader == null)
return null;
string s =myreader["field"].ToString();
}
}
I'm working on a small ASP.NET Core project for tagging images using Entity Framework Core on a Sqlite database, mainly just for learning. There are two tables (and POCOs), Tags and Images, where multiple tags are related to each image. I'm trying to get a count of all Images that have tags associated with them.
In plain SQL I'd write SELECT COUNT(DISTINCT ImageId) FROM Tags to get the count, and in LINQ I came up with _context.Tags.Select(t => t.Image).Distinct().Count(). But that LINQ query appears to cause EF-Core to join the two tables, return all of the rows, and then do the Distinct and Count in code.
I tried to do _context.Tags.FromSql("SELECT COUNT(DISTINCT ImageId) FROM Tags"), but because that query only returns the count the call fails because EF can't map the result to a Tag. I also tried to use _context.Database.FromSql<int>, but wasn't able to find any real documentation on it and there doesn't seem to be IntelliSense for it.
What I have done for now is what's detailed in the "ADO.NET" section of this blog post from Eric Anderson:
int count;
using (var connection = _context.Database.GetDbConnection())
{
connection.Open();
using (var command = connection.CreateCommand())
{
command.CommandText = "SELECT COUNT(DISTINCT ImageId) FROM Tags";
string result = command.ExecuteScalar().ToString();
int.TryParse(result, out count);
}
}
But is that the best way to go about getting the count efficiently?
Edit: Here's the query that EF is putting in the Debug output:
SELECT "t"."TagId", "t"."Content", "t"."ImageId", "t.Image"."ImageId", "t.Image"."FileName", "t.Image"."Path", "t.Image"."Url"
FROM "Tags" AS "t"
LEFT JOIN "Images" AS "t.Image" ON "t"."ImageId" = "t.Image"."ImageId"
ORDER BY "t"."ImageId"
As of now, you can't define an ad-hoc result.
Good news is that it's currently on the backlog: https://github.com/aspnet/EntityFramework/issues/1862
In the meantime, here's an extension method that would work:
public static int IntFromSQL(this ApplicationDbContext context, string sql )
{
int count;
using (var connection = context.Database.GetDbConnection())
{
connection.Open();
using (var command = connection.CreateCommand())
{
command.CommandText = sql;
string result = command.ExecuteScalar().ToString();
int.TryParse(result, out count);
}
}
return count;
}
Usage:
int result = _context.IntFromSQL("SELECT COUNT(DISTINCT ImageId) FROM Tags");
Your original line of code should have done exactly what you wanted. It would also be recommended over inline SQL.
_context.Tags.Select(t => t.Image).Distinct().Count()
Are you sure that this called the database for the two tables and then queried them in memory? If you observed this behaviour while debugging then it's possible that your inspection caused the IQueryable to enumerate which would call the database using a different query than it would have otherwise.
A way to check the actual query, without breaking into the running code, is by using the MyLoggerProvider from the Entity Framework Core documentation.
https://docs.efproject.net/en/latest/miscellaneous/logging.html?highlight=logging
Once the logger is registered in the code then any SQL query ran against the server will be displayed in the console window and/or in the file c:\temp\log.txt.
The following log message was generated when using a Distinct() and a Count() on the database tables of the website example.
SELECT COUNT(*)
FROM (
SELECT DISTINCT [a.Blog].[BlogId], [a.Blog].[Url]
FROM [Posts] AS [a]
INNER JOIN [Blogs] AS [a.Blog] ON [a].[BlogId] = [a.Blog].[BlogId]
) AS [t]Closing connection to database '***' on server 'tcp:**************'.
Finally, since you do not need any of the properties on the t.Image then it seems that you should be using a Where() rather than a Select().