How to perform a complex SQL query on DataTable objects? - c#

I am programming an Excel add-in in C# where I process data contained in different DataTable objects. I would like to provide a function to perform SQL queries on the data, with the ability to reference data from other tables in where and sort by clauses (for example, using a join).
An example of such a query would be
SELECT name
FROM Table1
WHERE id = Table2.id AND Table2.age > 18
The problem with this is that a DataTable doesn't know of the existance of the other DataTables, so (for so far I know) there are no such methods in the class. Also, I cannot use something like LINQ, since the query will be written by the users of the add-in in excel.
Would it be a good solution to copy the data to an in-memory database, where each DataTable is mapped to a table? How would this work performance-wise? Is there a simpler solution?

In terms of SQL query you are missing a table reference in selecting the tables, corrected query will look like
SELECT name
FROM Table1, Table2
WHERE Table1.id = Table2.id AND Table2.age > 18
Use Table1.name if there is same named attribute in Table2.
However using only WHERE condition in Joins without specifying the joining attribute is not recommended read this question. Use JOIN.
SELECT Table1.name
FROM Table1 INNER JOIN Table2 ON Table1.id = Table2.id WHERE Table2.age > 18

Related

How to join column from table2 to table1 after a specified column of table1?

I have a query like this:
Select table1.*, table2.column1 from table1 join table2 on table1.column1=table2.column1
It works, but it puts the column in the end of the datagridview, but i have to put table2.column1, after a specified column of table2, and i have to use table1.* and i cant use listing of the table1's columns is it possible?
And why exactly can't you use a list of all the fields?
NO , it's not possible to place a column in the middle of columns specified with * , not with pure SQL and not with dynamic.
Just specify them, don't be lazy, it's better practice:
SELECT table1.col1,
table1.col2,
table2.col1,
table1.col3
..........
because i am using union queries, and the table names are changing and one table contains more colums than the other
if table1 differs, that above all should be a strong argument for specifing all needed fields separatly. In case of a new field in table1, your query would be broken, cause the number of fields will differ from the ones used in the next union.

Efficient way to count related entities of a many to many relation in EF

I would like to know how to efficiently count (SQL server side) the amount of distinct count of results for a specific range of a related entity that has a many to many relationship.
This is the current situation in entity Framework:
Table1 1<------->∞ Table2
Table2 ∞<------->∞ Table4
Table 2 and Table 4 have a many to many relationship and are linked with Table3 in SQL.
What I want is the distinct count of table4 results related to a specific range of Table1.
In LinQ to SQL the query is this:
(from dc in Table1
join vc in Table2 on dc.Table1Id equals vc.Table2Id
join vcac in Table3 on vc.Table2Id equals vcac.Table3Id
join ac in Table4 on vcac.Table3Id equals ac.Table4Id
where dc.Table1Id > 200000
group ac by ac.Table4Id into nieuw
select new { acid= nieuw.Key}).Count()
This lets SQL server return the count directly.
Because the extra table for the many to many relation ( Table3) is gone, I have had problems converting this query to L2E in query syntax. ( since I cannot join table 4 with table 2 with an inner join).
I have this in chained syntax, however, is this efficient ( does this fetch the whole list, or does it let SQLserver do the count, as I'm not sure this is an efficient way to select, Table 2 contains about 30.000 entries, I don't want it to fetch this result just to count it):
context.Table4.Where(a => a.Table2.Any(v => v.Table1Id > 200000)).Select(a => aTable4Id).Distinct().Count();
How would I go converting the Linq2SQL query into L2E in the query syntax ? Or is the chained syntax fine in this situation ?
The .Select() method uses deferred execution, meaning it won't actually run the query until you need the results. At that point in the chain it still exists only as a query definition. Then you modify with .Distinct() before getting .Count() - which does query the database using a SQL GROUP BY statement. So you should be good.

Get name of all the tables used in SQL statement

I have dynamic SQL statement generated using criteria. This statement involves multiple joins using many tables. Requirement is to get list of all the tables used in this statement.
For example:
SELECT
table1.a, table2.b, ...
FROM
table1
INNER JOIN
table2 ON table1.col1 = table2.col1
LEFT OUTER JOIN
table3 ON table2.col3 = table3.col1
I want to get list of tables used in the above query dynamically like:
table1,table2,table3.
I am using C# and SQL Server. I think parsing the string and finding individual tables will be complex. Is there any way we can get the list of Tables used in a query from SQL Server itself?

Assign names to tables in an SQL Server result set

I am writing a stored procedure that executes several successive SELECT statements. When I execute this procedure via ADO.NET, my intention is to end up with a DataSet containing several DataTable objects. This behaves as expected.
I am currently relying on the order of the tables in the DataSet to match the order of the SELECT statements in the stored procedure, however there is really no significance in this order. The person who ultimately has to maintain the procedure shouldn't have to know the expected order of the results, nor should the person maintaining the application have to know the order of the statements in the procedure.
What I want to know is, is it possible to assign names to the result of each SELECT statement within the stored procedure itself, and then have these come through via ADO.NET (hopefully seamlessly) so that I can access each table by its name instead of its order?
e.g.
// populate DataSet with results from stored proc
DataSet ds = new DataSet();
dataAdapter.Fill(ds);
// now access one of the resulting DataTable via name
return ds.Tables["NamedResultFromTheProc"];
So, is there any way to achieve this? Or will I have to rely on the order of the SELECT statements and always access the desired table by its index?
I've not tried this but could you not change the structure of the stored proc so that you have a query returning the name of the table before each data query?
i.e.
select 'TableName';
select * from Table where 1 = 1;
then build the Dataset manually by creating tables and adding them in?
The tables returned by your query will be given the names "Table", "Table1", "Table2" etc.
You can add TableMappings to your DataAdapter before filling your DataSet to map them to your table names:
myAdapter.TableMappings.Add("Table", "MyTable1");
myAdapter.TableMappings.Add("Table1", "MyTable2");
myAdapter.TableMappings.Add("Table2", "MyTable3");
Unfortunately, I do not believe this is possible! I have a similar setup which gets DataSets from Stored Procedures, and after looking I gave up and resorted to indexes.
This is also not the best solution, but you could make the first column in your query be the table name:
Select 'Customer', CustomerID, CustomerName, CustomerAddress
From Customer
Where CustomerID = #CustomerID;
Select 'Orders', OrderID, OrderPrice, OrderDate
From Order O
Join Customer C on C.CustomerID = O.CustomerID
Where C.CustomerID = #CustomerID;
Select 'OrderItems', ItemID, ItemDescription, ItemPrice
From OrderItems I
Join Order O on O.OrderID = I.OrderID
Join Customer C on C.CustomerID = O.CustomerID
Where C.CustomerID = #CustomerID;
It is not possible, but its SQL "fault", not the fault of DataAdapter/Set, because result set does not carry the name of the table queried (nor is that discernibly possible if you use inner join) nor does the table adapter have a query from which to pick the name.
One method you can use is to first return a list of tables as Query#0 in the procedure, e.g.
select 'MyTable;MySecondTable;ThirdOrSo' as tables
followed by all other queries, then read index 0 table and this field, split/forloop to rename other tables in dataset. The maintainer would still need to know the mechanism but at least it gives him some freedom to reorganize..
I've been thinking about this as well and the only solution I can think of is to create temporary tables within the procedure and populate the results into there (naming the tables as you go).
I've not tried this yet because it doesn't feel like the right way to do it with having to get the results twice (query into temp table, query the temp table).
It would be really useful if you could just rename your result set in SQL in the same way you can rename "Column AS [Custom Column]"...

Using SubSonic Query to on multiple tables

I want to select rows from multiple tables using subsonic. For one table I can use Query object, but I don't know how I can add more than one tables to query.
You neet to join them, much like you would do in SQL.
If you have a foreign key relationship in the schema, Subsonic is smart enough to figure the joins directly:
DataSet DS = DB.Select().From<Table1>().InnerJoin<Table2>().ExecuteDataSet();
If you don't have a FKI between the tables, you need to manually specify the columns from each table to create the join:
DataSet DS = DB.Select().From<Table1>().InnerJoin(Table1.FKIColumn,Table2.IDColumn).ExecuteDataSet();
Similarly you can create the Left/Right Outer joins,etc.
Remeber you can only join them on simple FKI constraints. For example I found no easy way to do "INNER JOIN Table2 on Table1.FKI = Table2.ID and Table2.CreateDate>Table1.CreateDate" directly from SubSonic.
And a big downside to using SubSonic multiple table joins is that you will run into troubles if you have identically named columns in both tables.

Categories