dynamic sql generation is not supported against multiple base tables - c#

I tried to add a new row to a Table in an SQL DB, but I had a problem :
dynamic sql generation is not supported against multiple base tables
this is the code I tried :
private MyClass myClass = new MyClass();
private SqlDataAdapter adapter;
private SqlDataAdapter adapter2;
private void GestionCollections_Load(object sender, EventArgs e)
{
adapter = new SqlDataAdapter("select Id_Collection ID, Libelle_Collection Collection,Libelle_Editeur Editeur from Collection_ left join Editeur on Id_Editeur = Collection_.Id_Editeur_Editeur", myClass.cnx);
adapter.Fill(myClass.ds, "Collection_");
adapter2 = new SqlDataAdapter("Select Id_Editeur ID,Libelle_Editeur Editeur from Editeur", myClass.cnx);
adapter2.Fill(myClass.ds, "Editeur");
}
private void AjouterBarButton_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e)
{
String newKeyWordCollectionName = ajoutCollection.KeyWordCollectionName;
String newKeyWordAEditeurName = ajoutCollection.KeyWordEditeurName;
DataRow row = myClass.ds.Tables["Collection_"].NewRow();
row[1] = newKeyWordCollectionName;
foreach(var myRow in myClass.ds.Tables["Editeur"].AsEnumerable())
{
if (newKeyWordAEditeurName == myRow[1] as String)
row[2] = (int)myRow[0];
}
myClass.ds.Tables["Collection_"].Rows.Add(row);
SqlCommandBuilder builder = new SqlCommandBuilder(adapter);
adapter.Update(myClass.ds, "Collection_");
}

Change your select query and add distinct with inner join.
For example there are two query from which you can understand that what I want to tell you
Wrong query
select iop.pob_id, iop.pob_product_id, iop.pob_qty, iop.pob_unit_id
, iop.pob_rate, iop.pob_value, iop.pob_fiscalyear_id
, **p.product_desc** as orderBy from inv_product_open_balc iop
left join inv_product p on iop.pob_product_id = p.product_id
where p.product_desc like 'Air Freshner%' and iop.pob_fiscalyear_id = 3
Correct query
select distinct iop.pob_id, iop.pob_product_id, iop.pob_qty
, iop.pob_unit_id, iop.pob_rate, iop.pob_value, iop.pob_fiscalyear_id
, **(select Product_desc from** inv_product p where p.product_id = iop.pob_product_id )as orderBy
from inv_product_open_balc iop
inner join inv_product p on iop.pob_product_id = p.product_id
where p.product_desc like 'Air Freshner%' and iop.pob_fiscalyear_id = 3

You can't use an SqlCommandBuilder here:
Automatically generates single-table commands that are used to reconcile changes made to a DataSet with...
The key words here being "single-table". It has no way to reverse engineer from the SELECT statement how a specific update should be applied (e.g. if you NULL all of the columns from the right side of a left join, should it delete the row, or set each column to null.
You need to author appropriate Insert, Update and Delete commands on the SqlDataAdapter.

With SqlCommandBuilder you can generate CRUD operation on entity
Requirement of use is to define Select command before inserting , and include in the select command your primary Key.
Link : http://msdn.microsoft.com/fr-fr/library/system.data.sqlclient.sqlcommandbuilder(v=vs.80).aspx
MSDN Definition : Automatically generate Transact-SQL statements to update single table
Nota : In your Update selectCommand, you defined left join query, and so you can create left join query, replace this query with just select.

Add DISTINCT in your select statement with inner join.
This will solve the issue.
like Select Distinct Employee.Ecode, .........

Related

Building SQL IN statement from listbox control Return Nothing

I have a ListBox with multiple select values. I am trying to fetch data from the Employees table. Depending on values from this ListBox I tried to use in statement. I checked the query and it's true but still didn't fetch any data without any errors.
Here is the code:
StringBuilder sb = new StringBuilder("SELECT * FROM Emp_Attend LEFT JOIN Employees on Emp_Attend.Emp_ID = Employees.EmpID WHERE ");
StringBuilder sb = new StringBuilder("SELECT * FROM Emp_Attend LEFT JOIN Employees on Emp_Attend.Emp_ID = Employees.EmpID WHERE ");
using (SqlCommand cmdSQL = new SqlCommand())
{
sb.Append("Emp_Attend.Emp_Name IN (");
string InPartQuery = string.Join(",", ListBox1.Items
.Cast<ListItem>()
.Where(t => t.Selected)
.Select(r => "'" + r.Text + "'"));
sb.Append(InPartQuery);
sb.Append(")");
cmdSQL.CommandText = sb.ToString();
cmdSQL.Connection = sqlcon;
SqlDataAdapter da = new SqlDataAdapter(cmdSQL);
DataTable dtbl = new DataTable();
da.Fill(dtbl);
sqlcon.Close();
gvEmployees.DataSource = dtbl;
gvEmployees.DataBind();
The best idea is to use parameters rather than string concatenation. The following code can be found in my GitHub repository were the following class project provides methods to create parameters and the frontend project.
The following may appear overkill while using parameters is keeping your data in parameters safe/hidden from prying eyes. All code is available on GitHub via links in the post below. In the screenshot below the first two examples are not parameterized while the third (button Hard Coded) is completely parameterized.
The following class method will generate a SQL WHERE IN without parameters but handles formatting e.g. apostrophes in string and leaves numerics alone.
In the following screenshot the two group boxes demo the above.
For parameterized there is BuildWhereInClause(string partialClause, string paramPrefix, IEnumerable parameters). Where in the following code sample BuildWhereInClause creates the SQL while AddParamsToCommand creates the parameters for the SQL statement which generated
SELECT C.CustomerIdentifier , C.CompanyName , C.ContactName , C.ContactTypeIdentifier , FORMAT(C.ModifiedDate, 'MM-dd-yyyy', 'en-US') AS ModifiedDate, CT.ContactTitle FROM dbo.Customers AS C INNER JOIN dbo.ContactType AS CT ON C.ContactTypeIdentifier = CT.ContactTypeIdentifier WHERE CT.ContactTitle IN (#CTContactTitle0,#CTContactTitle1) ORDER BY C.CompanyName
You can get all the selected items and store them in a variable then use it in your command like below:
List<string> ids = new List<string>();
foreach (var item in listBox1.SelectedItems)
{
ids.Add(item.ToString());
}
string command = $"SELECT * FROM Emp_Attend LEFT JOIN Employees on Emp_Attend.Emp_ID = Employees.EmpID WHERE Emp_Attend.Emp_Name in ({string.Join(",",ids)})";
but I recommend you to make it parametric in order to avoid SQL Injection

How to get different rows from two tables in SQL Server

I'm trying to build a query that can give me the different rows between two tables.
Here is my code:
try
{
string searchquery = "SELECT* FROM NewList EXCEPT SELECT* FROM Restaurants UNION All";
SqlCommand searchcom = new SqlCommand(searchquery, connection);
SqlDataAdapter da = new SqlDataAdapter(searchcom);
DataSet ds = new DataSet();
connection.Open();
da.Fill(ds);
dataGridView1.DataSource = ds.Tables[0];
connection.Close();
}
catch (Exception er)
{
Debug.WriteLine(er.Message);
return;
}
I get the following error:
Incorrect syntax near 'All'.
What is the correct way/syntax to use Union All in SqlCommand class? I've tried to put it it my query string in too many ways but it's giving me the same error every time. How can I implement it in my search query with correct syntax ?
Your query is incorrect from UNION ALL on.
You can try it like this:
string searchquery = "SELECT * FROM NewList UNION ALL SELECT * FROM Restaurants ";
However, you need to be aware that:
It does not remove duplicate rows between the various SELECT statements (all rows are returned)
Each SELECT statement within the UNION ALL must have the same number of columns in the result sets with similar data types
Read here for more details.
Updated
You should use EXCEPT instead of UNION ALL if you want to get rows in one table that are not present in the other one.
Select Checking.RestID, FROM
(SELECT RestID FROM NewList EXCEPT Select RestID from Restaurants) as Checking
LEFT JOIN NewList ON Checking.RestID = NewList.RestID
this worked, thanks to anyone !

Database table not showing data after inner join

I have a C# windows forms application and I'm working with a database too.
I have 3 tables: Players, Tournaments and TournamentsPlayers.
I will only show 2 tables in the form, the Tournaments and the Players tables. The Tournaments table has a column which is a checkbox and I want to show in the Players table only the players from the tournaments which I checked the box.
When the application starts I have a foreach statement which check all the tournaments, so at first all the players should show in the Players table, but no player is shown.
My code is:
private void ShowPlayersForSelectedTournaments()
{
string query =
"SELECT a.Name, a.Id FROM Players a,TournamentPlayers b WHERE a.Id=b.TournamentId AND b.TournamentId=#TournamentId";
using (Connection = new SqlConnection(ConnectionString))
using (SqlCommand command = new SqlCommand(query, Connection))
using (SqlDataAdapter adapter = new SqlDataAdapter(command))
{
foreach (DataGridViewRow row in TournamentsTable.Rows)
{
if (row.Cells.Count > 0 && bool.Parse(row.Cells[0].Value.ToString()))
{
command.Parameters.AddWithValue("#TournamentId", row.Cells[1].Value);
DataTable tournamentPlayersList = new DataTable();
adapter.Fill(tournamentPlayersList);
PlayersTable.DataSource = tournamentPlayersList;
break;
}
}
}
}
I have tried a simple select and all is working, but with this sql syntax it doesn't seems to work.
I have tried with another similar mysql syntax, like:
string query = "SELECT a.Name FROM Players a INNER JOIN TournamentPlayers b ON a.Id=b.TournamentId WHERE b.TournamentId=#TournamentId";
But still nothing shows in the Players table.
What am I doing wrong? Is there something wrong with my mysql syntax or my code?
This is your query:
SELECT a.Name, a.Id
FROM Players a,TournamentPlayers b
WHERE a.Id=b.TournamentId AND b.TournamentId=#TournamentId;
It has multiple problems. This should work:
SELECT p.Name, p.Id
FROM Players p JOIN
TournamentPlayers tp
ON tp.playerId = p.id
WHERE tp.TournamentId = #TournamentId;
Notes:
Never use commas in the FROM clause. Always use proper, explicit JOIN syntax.
Use abbreviations for the table names, so the query makes sense when read.
FIx the join condition between the tables, to match on the player. It is highly unlikely that a player has the same id as a tournament and also played in that tournament. Possible, but unlikely.

sql command error in C#

I have written this code to retrieve some information from two tables in database. But when I run it I get this error
Column 'Eaten_food.Cardserial' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
Code:
private void button8_Click(object sender, EventArgs e)
{
using (SqlConnection con = new SqlConnection(WF_AbsPres_Food.Properties.Settings.Default.DbConnectionString))
{
con.Open();
SqlDataAdapter a = new SqlDataAdapter("SELECT Eaten_food.Cardserial , Eaten_food.Date , Eaten_food.Turn , Avb_food_count , Reserve_count from Reserve inner join Eaten_food on Reserve.Cardserial = Eaten_food.Cardserial group by Eaten_food.Date", con);
SqlCommandBuilder comdBuilder = new SqlCommandBuilder(a);
DataTable t = new DataTable();
//t.Locale = System.Globalization.CultureInfo.InvariantCulture;
a.Fill(t);
bindingSource3.DataSource = t;
/// bind the grid view with binding source
Reserve_dataGridView.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.AllCellsExceptHeader);
Reserve_dataGridView.ReadOnly = true;
Reserve_dataGridView.DataSource = bindingSource3;
Reserve_dataGridView.DataSource = t;
con.Close();
}
}
How can I solve it?
The problem is your sql query. If you use Group By you cannot select columns that are not grouped by or that are not aggregated(f.e. by using Min/Max/Avg/Count).
So you could make it working for example in this way, change your old query here:
SELECT eaten_food.cardserial,
eaten_food.date,
eaten_food.turn,
avb_food_count,
reserve_count
FROM reserve
INNER JOIN eaten_food
ON reserve.cardserial = eaten_food.cardserial
GROUP BY eaten_food.date
to:
SELECT MIN(eaten_food.cardserial)AS Cardserial,
eaten_food.date,
MIN(eaten_food.turn) AS Turn,
SUM(avb_food_count) AS SumFoodCount,
SUM(reserve_count) AS SumReserveCount
FROM reserve
INNER JOIN eaten_food
ON reserve.cardserial = eaten_food.cardserial
GROUP BY eaten_food.date
You have a problem with you SQL statement itself. I would copy it to SQL management studio and debug it.
The group function is to create summary rows and because of that your select columns would either need to be part of the group by clause or a summary type of statmet like sum(x) or count(x)
The following might work..
SELECT Eaten_food.Cardserial ,
Eaten_food.Date ,
Count(Eaten_food.Turn) ,
sum(Avb_food_count) ,
sum(Reserve_count)
FROM Reserve
INNER JOIN Eaten_food ON Reserve.Cardserial = Eaten_food.Cardserial
GROUP BY Eaten_food.Date, Eaten_food.CardSerial

Find underlying tables of views using Linq to Entity to make Aggregate Dependencies

I have a function:
public static List<T> EntityCache<T>(this System.Linq.IQueryable<T> q, ObjectContext dc, string CacheId)
{
try
{
List<T> objCache = (List<T>)System.Web.HttpRuntime.Cache.Get(CacheId);
string connStr = (dc.Connection as System.Data.EntityClient.EntityConnection).StoreConnection.ConnectionString;
if (objCache == null)
{
ObjectQuery<T> productQuery = q as ObjectQuery<T>;
string sqlCmd = productQuery.ToTraceString();
using (System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection(connStr))
{
conn.Open();
using (System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand(sqlCmd, conn))
{
string NotificationTable = q.ElementType.Name;
System.Web.Caching.SqlCacheDependency sqldep = new System.Web.Caching.SqlCacheDependency(cmd);
cmd.ExecuteNonQuery();
objCache = q.ToList();
System.Web.HttpRuntime.Cache.Insert(CacheId, objCache, sqldep);
}
}
}
return objCache;
}
catch (Exception ex)
{
throw ex;
}
}
q can be a table, view or a procedure.
What i want is to find the underlying tables associated with a view or a procedure.
like if q is a join of tow tables i want to get the name of both the tables and finally
execute like:
If there are tw0 tables say A and B
Then i need to make Aggregate Dependency like:
string sqlCmd1 = string.Empty;
string sqlCmd2 = string.Empty;
using (testEntities ctx1 = new testEntities())
{
sqlCmd1 = ((System.Data.Objects.ObjectQuery)(from p in ctx1.A select p)).ToTraceString();
sqlCmd2 = ((System.Data.Objects.ObjectQuery)(from p in ctx1.B select p)).ToTraceString();
}
System.Data.SqlClient.SqlCommand cmd1 = new System.Data.SqlClient.SqlCommand(sqlCmd1, conn);
System.Data.SqlClient.SqlCommand cmd2 = new System.Data.SqlClient.SqlCommand(sqlCmd2, conn);
System.Web.Caching.SqlCacheDependency
dep1 = new System.Web.Caching.SqlCacheDependency(cmd1),
dep2 = new System.Web.Caching.SqlCacheDependency(cmd2);
System.Web.Caching.AggregateCacheDependency aggDep = new System.Web.Caching.AggregateCacheDependency();
aggDep.Add(dep1, dep2);
cmd1.ExecuteNonQuery();
cmd2.ExecuteNonQuery();
then the query i want to execute is
select * from A;
select * from B;
This i am using for SqlCacheDependency using Linq to Entity.
It works well for views when i hardcode the underlying tables but now i want the code automatically check for the underlying tables
and execute nonquery like
cmd1.ExecuteNonQuery();
cmd2.ExecuteNonQuery();
and make aggregate dependencies.
Any help is appreciated.
Thanks.
You must use database level tools to find which database objects your views or stored procedures depends on (but it also means you must know their full names in the database). For example SQL server offers sp_depends system stored procedure to track dependencies. This can be quite complicated because dependencies can have multiple levels (procedure can be dependent on view, view can be dependent on another view, etc.).
Be aware that advanced EF mapping also allows writing SQL directly to EDMX and in such case you will have to parse ToTraceString to find database objects.
I have found a solution for the problem i have posted.
There is a query that is valid for sql server 2005 onward.
We need to pass the name of the object and it will return us the name of the tables on which it depends
Example:
The name of the View is say AllProducts_Active_Inactive
;WITH CTE AS (SELECT o.name
, o.type_desc
, p.name
, p.type_desc as B
, p.object_id
FROM sys.sql_dependencies d
INNER JOIN sys.objects o
ON d.object_id = o.object_id
INNER JOIN sys.objects p
ON d.referenced_major_id = p.object_id
where o.name = 'AllProducts_Active_Inactive'
UNION ALL
SELECT o.name
, o.type_desc
, p.name
, p.type_desc as B
, p.[object_id]
FROM sys.sql_dependencies d
INNER JOIN CTE o
ON d.object_id = o.object_id
INNER JOIN sys.objects p
ON d.referenced_major_id = p.object_id
where o.name = 'AllProducts_Active_Inactive'
)
SELECT DISTINCT * FROM [CTE]
where B = 'USER_TABLE'
This post is the modified answer of the question i have posted on the website:
http://ask.sqlservercentral.com/questions/81318/find-the-underlying-tables-assocaited-with-a-view-or-a-stored-procedure-in-sql-server
What i changed is added the line where B = 'USER_TABLE'
Which means only those dependencies are returned who are tables.
And the seconds thing is added a WHERE clause so that a specific object is found.
Thanks

Categories

Resources