MySQL query works in Workbench but not in C# code - c#

SQL query:
SELECT som.id, som.name, som.search_enabled, oc.id, oc.name
FROM option_category oc
INNER JOIN skill_option so
on oc.id=so.option_category_id
INNER JOIN skill_option_master som
on som.id=so.id;
Works fine in Workbench:
However, within my C# code:
List<string> listItems = getMultiColumnListFromDB(
"SELECT som.id, som.name, som.search_enabled, oc.id, oc.name " +
"FROM option_category oc " +
"INNER JOIN skill_option so " +
" on oc.id=so.option_category_id " +
"INNER JOIN skill_option_master som " +
" on som.id=so.id; "
,new string[] { "som.id", "som.name", "som.search_enabled", "oc.id", "oc.name" });
...
private List<string> getMultiColumnListFromDB(string query, string[] columnNames)
{
List<string> result = new List<string>();
MySqlConnection con = new MySqlConnection(dbConnectionString);
MySqlCommand cmd = new MySqlCommand(query, con);
con.Open();
MySqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
string strResult = "";
foreach (string columnName in columnNames)
{
if (reader[columnName] == DBNull.Value)
//If value is NULL, we assume yes/1
strResult = strResult + "1" + ";";
else
strResult = strResult + reader[columnName].ToString() + ";";
}
result.Add(strResult.TrimEnd(';'));
}
return result;
}
...I get: System.IndexOutOfRangeException: 'Could not find specified column in results: som.id' at Line: if (reader[columnName] == DBNull.Value)
As a test, I copied the query from the Exceptions window whilst debugging back into Workbench and it worked without any modifications required1. Simpler queries (without joins) work fine within my app. I appreciate my code isn't the most elegant but I can't get over 1 above. How can that be?
Thanks

Modified SQL query to alias the column names:
SELECT som.id as 'som.id', som.name as 'som.name', som.search_enabled as 'som.search_enabled', oc.id as 'oc.id', oc.name as 'oc.name'
FROM option_category oc
INNER JOIN skill_option so
on oc.id=so.option_category_id
INNER JOIN skill_option_master som
on som.id=so.id;

Related

'Incorrect syntax near GROUP, What does it mean when it is an incorrect syntax?

I am creating a form that I can add a menu item to display All Suppliers and Suppliers Quantity by Part number. So I got ReportSupplierDisplayALl to work when I ran. But When I try to run the form for the ReportSuppliersDisplayByPartnumber because When I enter the SupplierID and when I did it threw an exception.
When it throws an exception, what does it mean by incorrect syntax?
public DataTable DisplaySupplierByPartNumber(string PartNumber)
{
// Add using System.Data
string queryString = "SELECT Suppliers.SupplierName, Suppliers.Email, Parts.PartName, SUM(Inventory.Quantity) AS SumOfQuantity, PartNumber " +
"FROM ((Suppliers INNER JOIN Parts ON Suppliers.SupplierID = Parts.Supplier) INNER JOIN Inventory ON Parts.PartNumber = Inventory.PartNumber " +
"INNER JOIN Employees ON Inventory.EmpID = Employees.EmpID " +
"GROUP BY Suppliers.SupplierName, Suppliers.Email, Parts.PartName, Parts.PartNumber " +
"HAVING Parts.PartNumber = #PartNumber " +
"ORDER BY Suppliers.SupplierName ";
using (SqlConnection con = new SqlConnection(_strCon))
{
try
{
SqlCommand command = new SqlCommand(queryString, con);
command.Parameters.AddWithValue("#PartNumber", PartNumber );
con.Open();
SqlDataReader reader = command.ExecuteReader();
DataTable theTable = new DataTable();
theTable.Load(reader);
return theTable;
}
catch (Exception ex)
{
throw ex;
}
}
enter image description here
enter image description here
Don't use "" For String use # "Your Query And Make Sure You get all bracket correct"
also change element take part number first then use your aggerate function
string queryString = #"SELECT S.SupplierName, S.Email, P.PartName, SUM(Inventory. Quantity) AS SumOfQuantity FROM Suppliers as s
INNER JOIN Parts as p on P.SupplierId=P.SupplierId
INNER JOIN Inventory ON Parts.PartNumber = Inventory.PartNumber
INNER JOIN Employees ON Inventory.EmpID = Employees.EmpID
GROUP BY S.SupplierName, S.Email, P.PartName, P.PartNumber
HAVING Parts.PartNumber = #PartNumber
ORDER BY S.SupplierName"

Selecting whole row in Mysql database using C# and saving it as a list

I'm trying to select one specific row from my mysql database.
In SQL I'd just use
select * from endkunden where id = 2;
this works just fine, I get everything I want.
Now I want to do this in my c# code and save the data into a string list.
I tried doing it like this
public List<string> SelectListRow(string target, string table,string idef, int id)
{
string query = "SELECT " + target + " FROM " + table + " where "+ idef + " = " +id;
List<string> list = new List<string>();
if (this.OpenConnection())
{
MySqlCommand cmd = new MySqlCommand(query, connection);
MySqlDataReader dataReader = cmd.ExecuteReader();
while (dataReader.Read())
{
list.Add(Convert.ToString(dataReader[target]));
}
dataReader.Close();
this.CloseConnection();
return list;
}
return list;
}
Since this worked for selecting all columns in the table using
select compname from endkunden;
I assumed, that this would work with rows as well, but it doesn't. When using it like this
I use the following query:
select *
from endkunden
where id = 2
but now I get an error:
System.IndexOutOfRangeException
HResult=0x80131508
Nachricht = Could not find specified column in results: *
Quelle = MySql.Data
Stapelüberwachung:
at MySql.Data.MySqlClient.ResultSet.GetOrdinal(String name)
at MySql.Data.MySqlClient.MySqlDataReader.GetOrdinal(String name)
at MySql.Data.MySqlClient.MySqlDataReader.get_Item(String name)
at MySQL_Tests.DBAC.SelectListRow(String target, String table, String idef, Int32 id) in C:\Users\Murf\source\repos\MySQL Tests\MySQL Tests\DBAC.cs:line 187
at MySQL_Tests.Program.Main(String[] args) in C:\Users\Murf\source\repos\MySQL Tests\MySQL Tests\Program.cs:line 13
Nachricht means message, quelle means error, stapelüberwachung means .. i don´t know
Any ideas how to fix this?
Greetings,
Murf
Since you are passing * it seems that you want multiple columns instead of just the first one.
public List<string> SelectListRow(string target, string table,string idef, int id)
{
string query = "SELECT " + target + " FROM " + table + " where "+ idef + " = " +id;
List<string> list = new List<string>();
if (this.OpenConnection())
{
MySqlCommand cmd = new MySqlCommand(query, connection);
MySqlDataReader dataReader = cmd.ExecuteReader();
while (dataReader.Read())
{
for (int i = 0; i < dataReader.FieldCount; i++) {
{
list.Add(dataReader.GetString(i));
}
}
dataReader.Close();
this.CloseConnection();
return list;
}
return list;
}
That will get you the values that you require.
One additional thing I noticed is that if there is an exception that the connection data reader arent cleaned up. You can fix this by using try block with a finally clause or wrapping these in 'using' blocks.
Instead using the data reader with the column name use
dataReader.GetString(0) which would give the first column.
public List<string> SelectListRow(string target, string table,string idef, int id)
{
string query = "SELECT " + target + " FROM " + table + " where "+ idef + " = " +id;
List<string> list = new List<string>();
if (this.OpenConnection())
{
MySqlCommand cmd = new MySqlCommand(query, connection);
MySqlDataReader dataReader = cmd.ExecuteReader();
while (dataReader.Read())
{
list.Add(dataReader.GetString(0));
}
dataReader.Close();
this.CloseConnection();
return list;
}
return list;
}

Executing a query with no search term causes System.StackOverflow Exception in System.Runtime.Serialization.dll

I 'm dealing with a query which results in above mentioned error when called with no or limited search string.
The table is 30k records big and when the query is fired with no search string I would expect the database to return all records and have Visual Studio put them in a table (ASP.net), however, if the query is fired like above the StackOverflow error is returned :(
If I fire the query with a more specific search string the script seems to work normal and results are being returned as expected.
I have been googling and all seems to point to an infinite loop or recursion but returning records make me believe it might be another problem.
The query:
SqlConnection conn = new SqlConnection(_cstring);
SqlCommand cmd = new SqlCommand();
cmd.Connection = conn;
conn.Open();
SqlDataReader dr;
if (mode == "zoek_met_zoekterm")
{
cmd.CommandText = "select W1.id, W1.soort_brief, W1.omschrijving, W1.referentie, W1.url, W1.factuur, W3.naam, W3.klantnummer, W4.omschrijving AS w4_omschr, W4.referentie AS w4_ref, substring(W1.referentie,6,2) as w1_jaar, W1.parent AS w1_parent from brief W1 left join brief W4 on W1.parent = W4.id join klant W3 on W3.klantnummer = W1.klantnummer where W1.referentie in (select referentie from brief where substring(referentie,6,2) = #jaar) and (W3.klantnummer like #zoekterm or W1.referentie like #zoekterm or W1.omschrijving like #zoekterm or W3.naam like #zoekterm or W4.omschrijving like #zoekterm) order by W1.id";
cmd.Parameters.Clear();
cmd.Parameters.Add("#zoekterm", SqlDbType.VarChar).Value = "%" + (string)parameters["zoekterm"] + "%";
string jaar = parameters["jaar"].ToString();
jaar = jaar.Substring(2, 2);
cmd.Parameters.Add("#jaar", SqlDbType.VarChar).Value = jaar;//(Int32)parameters["jaar"];
base.LogQuery(cmd);
dr = cmd.ExecuteReader();
while (dr.Read())
{
CBrief brief = new CBrief();
brief.Id = dr.GetInt32(0);
brief.SoortBrief = (Enums.SoortBrief)dr.GetInt32(1);
brief.Omschrijving = Functies.Decrypt(dr.GetString(2), EncryptData);
brief.Referentie = Functies.Decrypt(dr.GetString(3), EncryptData);
brief.Url = Functies.Decrypt(dr.GetString(4), EncryptData);
brief.Factuur = (Enums.SoortDocument)dr.GetInt32(5);
brief.Klantnummer = dr.GetInt32(7);
if (dr.GetString(2).Length == 0)
{
if (!dr.IsDBNull(9) && !dr.IsDBNull(8))
brief.Omschrijving = dr.GetString(9) + " " + dr.GetString(8);
}
ret_value.Add(brief);
}
dr.Close();
dr.Dispose();
}
And the function that calls the query:
public List<CBrief> GetBriefOverzicht(string zoekterm, int jaar)
{
Dictionary<string, object> parameters = new Dictionary<string, object>();
parameters.Add("zoekterm", zoekterm);
parameters.Add("jaar", jaar);
if (zoekterm.Length == 0)
{
return _dal.brief_search(parameters, "geen_invoer");
}
return _dal.brief_search(parameters, "zoek_met_zoekterm");
}
And last but not least the function that builds the table to display in the web application:
protected void Bzoeken_Click(object sender, EventArgs e)
{
string zoekterm = TBzoekterm.Text;
DateTime nu = DateTime.Now;
int jaar = nu.Year;
List<CBrief> brieven = br_rbs.GetBriefOverzichtWijzigen(zoekterm);
StringBuilder overzicht = new StringBuilder("<table class=\"tabel-beheer-1\">");
foreach (CBrief b in brieven)
{
List<CBijlage> bijlagen = new List<CBijlage>();
CKlant k = sec.GetKlant(b.Klantnummer);
string klantnaam = k.Naam;
string richting = "";
if (b.OmschrijvingAanwezig == true)
{
bijlagen = br_rbs.GetBijlagenBrieven(b.Id);
}
if (b.SoortBrief == Enums.SoortBrief.Inkomend) richting = "van: "; else richting = "naar: ";
// MG10082017 Ik heb hier twee icoontjes in elkaar geflanst om te testen. Deze moeten nog aangepast worden zodat ze in het geheeel passen.
overzicht.AppendLine("<tr><td><img src=\"/images/bg/document.jpg\" alt=\"open document\"></td><td><img src=\"/images/bg/detail.jpg\" alt=\"details\"></td><td><b>" + b.Referentie + "</b></td><td><i>" + b.SoortBrief.ToString() + " " + richting + "</i> " + klantnaam + "</td><td><b> " + b.Factuur.ToString() + ":</b> " + b.Omschrijving /*+"</td><td>"*/);
if (bijlagen.Count > 0)
{
foreach (CBijlage bijl in bijlagen)
{
overzicht.AppendLine("</br> " + bijl.Naam + "");
}
}
}
overzicht.AppendLine("</td></tr></table>");
Loverzicht.Text = overzicht.ToString();
}
The error usually points to: System.Web.dll or w3wp.exe (when not ran in debug mode). If my assumption is wrong and it seems to be an infinite loop or recursion, how am I going to find this?
The query works flawless in MS-SQL management console.
The Problem is not an infinite loop!
The Problem lies in the UI.
You can't display 30k units at once without a StackOverflow-Exception.
You should call pages of maybe 20 or 30 units at once with an pageIndex.
This way, your application will perform better and avoid such errors.

TSQL merge Incorrect syntax near ','

Getting SQLException with this "super useful" exception message (Incorrect syntax near ','.) , was wondering if anyone could see anything wrong with the syntax at a glace?
It is code based off of the example that can be found at http://www.jarloo.com/c-bulk-upsert-to-sql-server-tutorial/
private void importToolStripMenuItem_Click(object sender, EventArgs e)
{
DataTable import = new DataTable();
DialogResult result = this.importFileDialog.ShowDialog();
if (DialogResult.OK == result)
{
Stream importStream = this.importFileDialog.OpenFile();
import.ReadXml(importStream);
importStream.Close();
string tmpTable = "select top 0 * into #import from tblJob;";
using (SqlConnection con = new SqlConnection(CONSTRING))
{
con.Open();
SqlCommand cmd = new SqlCommand(tmpTable, con);
cmd.ExecuteNonQuery();
SqlBulkCopyOptions options = SqlBulkCopyOptions.KeepIdentity;
using (SqlBulkCopy bulk = new SqlBulkCopy(con))
{
bulk.DestinationTableName = "#import";
bulk.WriteToServer(import);
}
//http://www.jarloo.com/c-bulk-upsert-to-sql-server-tutorial/
//Now use the merge command to upsert from the temp table to the production table
string mergeSql = "merge into tblJob as Target " +
"using #import as Source " +
"on " +
"Target.[Location]=Source.[Location]," +
"Target.[Schedule]=Source.[Schedule] " +
"when matched then " +
"update set Target.[Complete]=Source.[Complete]," +
"Target.[Cost]=Source.[Cost]," +
"Target.[Description]=Source.[Description]";
//"when not matched then " +
//"insert (Symbol,Price,Timestamp) values (Source.Symbol,Source.Price,Source.Timestamp)" +
//";";
cmd.CommandText = mergeSql;
cmd.ExecuteNonQuery();
//Clean up the temp table
cmd.CommandText = "drop table #import";
cmd.ExecuteNonQuery();
}
dgvJobs.DataSource = getData("select * from tblJob");
If you want to have multiple Join criteria in your MERGE, you need to use the AND keyword (not a comma ,, as you're using now).
Instead of
merge into tblJob as Target
using #import as Source on Target.[Location]=Source.[Location], Target.[Schedule]=Source.[Schedule]
that you're using, use this instead:
MERGE INTO dbo.tblJob AS Target
USING #import AS Source ON Target.[Location] = Source.[Location]
AND Target.[Schedule] = Source.[Schedule]
This is true for any join condition, also for INNER JOIN and LEFT OUTER JOIN or any other join type, too.

How to use Linq instead of SQL Injection query for custom search

I would like to use Linq instead of below hardcoded Sql Injection to search from SqlServer DATABASE TABLES. How to retrieve Dynamically generated web controls input texts in C# Linq and replace the entire Sql injection in Linq for searching.
My C# code:
protected void Search_Button_Click(object sender, EventArgs e)
{
try
{
Table maintable = Select.FindControl("dynamic_filter_table_id") as Table;
int rc = maintable.Rows.Count;
if (rc == 1)
{
DropDownList D1 = maintable.FindControl("MainDDL") as DropDownList;
if (D1.SelectedValue.Contains("decimal"))
{
TextBox T1 = maintable.FindControl("txtbox1") as TextBox;
TextBox T2 = maintable.FindControl("txtbox2") as TextBox;
SqlDataAdapter sql = new SqlDataAdapter("SELECT F.Col1,F.Col2,V.COL1, col2,col3, col4 , col5, cl6 FROM TABLE1 as V , TABL2 as F WHERE V.Col1 = F.Col1 AND " + DDL1.SelectedItem.Text + " >= " + T1.Text + " AND " + DDl1.SelectedItem.Text + " <= " + T2.Text, con);
DataSet data = new DataSet();
sql.Fill(data);
con.Close();
Session["DataforSearch_DDL"] = data.Tables[0];
}
}
}
catch
{
ImproperSearch();
}
}
Why don't you just rewrite your query to be SQL-injection safe? LINQ won't give you any benefit.
You can achieve that by doing two things.
The first is to secure the column names. That is accomplished by specifying which characters is allowed for column names (more secure than trying to figure out what characters is not allowed). In this case I remove everything but letters and digits. If you have column names which contains underscore, just add that to the check.
The next thing is to use parameterized queries. Each ADO.NET driver has built in support for that, so you just have to specify the value using cmd.Parameters.AddWithValue. By doing so the value isn't part of the query string and hence there is no potential SQL injection.
using (var con = yourConnectionFactory.Create())
{
using (var cmd = new SqlCommand(con))
{
var safeKey1 = OnlyLettersAndDigits(DDL1.SelectedItem.Text);
var safeKey2 = OnlyLettersAndDigits(DDL2.SelectedItem.Text);
cmd.CommandText = "SELECT F.Col1,F.Col2,V.COL1, col2,col3, col4 , col5, cl6 " +
" FROM TABLE1 as V , TABL2 as F WHERE V.Col1 = F.Col1 " +
" AND " + safeKey1 + " >= #text1 " +
" AND " + safeKey2 + " <= #text2 ";
cmd.Parameters.AddWithValue("text1", T1.Text);
cmd.Parameters.AddWithValue("text2", T2.Text);
var adapter = new SqlDataAdapter(cmd);
var data = new DataSet();
sql.Fill(data);
Session["DataforSearch_DDL"] = data.Tables[0];
}
}
public string OnlyLettersAndDigits(string value)
{
var stripped = "";
foreach (var ch in value)
{
if (char.IsLetterOrDigit(ch))
stripped += ch;
}
return stripped;
}
You can use store procedure for customer search, It will work for both ADO.Net and LINQ approach. Just create a SP and add it to your DBML file very simple.
Here is the link how you can use SP in LINQ
http://www.mssqltips.com/sqlservertip/1542/using-stored-procedures-with-linq-to-sql/

Categories

Resources