Linq to SQL: Group By and Sum() - asp.net

I'm very new to linq so this should be pretty easy to answer, but I've had a hard time finding the answer.
I have the following LINQ statement, which performs a simple linq query and assigns the resulting values labels on an asp.net web form:
Dim db As New MeetingManagerDataContext
Dim q = From s In db.vwRoomAvailabilities _
Where s.MeetingID = lblMeetingID.Text _
Select s.AllRequestedSingles, s.AllRequestedDoubles, s.AllBookedSingles, s.AllBookedDoubles, SinglesNeeded = s.AllRequestedSingles - s.AllBookedDoubles, DoublesNeeded = s.AllRequestedDoubles - s.AllBookedDoubles
lblSinglesRequested.Text = "Singles Requested: " & q.FirstOrDefault.AllRequestedSingles
lblSinglesBooked.Text = "Singles Booked: " & q.FirstOrDefault().AllBookedSingles
lblSinglesNeeded.Text = "Singles Needed: " & q.FirstOrDefault().SinglesNeeded
lblDoublesRequested.Text = "Doubles Requested: " & q.FirstOrDefault().AllRequestedDoubles
lblDoublesBooked.Text = "Doubles Booked: " & q.FirstOrDefault().AllBookedDoubles
lblDoublesNeeded.Text = "Doubles Needed: " & q.FirstOrDefault().DoublesNeeded
Originally, there was going to be only a single row result and you can see I'm using FirstOrDefault() to grab that single value which works great. But the design has changed, and multiple rows can now be returned by the query. I need to now Group By the MeetingID above, and SUM each of the selected columns (i.e. s.AllRequestedDoubles).
I've found lots of grouping and summing samples but none seem to fit this scenario very well.
Can you help me modify the above LINQ to Sum the resulting values instead of just showing the first row result values?

Try this
From s In db.vwRoomAvailabilities
Where s.MeetingID = lblMeetingID.Text
Group by s.MeetingID
into SumAllRequestedDoubles = sum(s.AllRequestedDoubles),
SumAggregate2 = sum(s.SomeField2),
SumAggregate3 = sum(s.SomeField3)
Select SumAllRequestedDoubles, SumAggregate2, SumAggregate3
That will get you started for performing a SUM on that single column.
You'll need to project each SUM'd column into a new aliased column (like i did above).
Also, as you're new to LINQ-SQL, check out LinqPad - it will rock your world.

Related

How to execute a complex sql statement and get the results in an array?

I would like to execute a fairly complex SQL statement using SQLite.swift and get the result preferably in an array to use as a data source for a tableview. The statement looks like this:
SELECT defindex, AVG(price) FROM prices WHERE quality = 5 AND price_index != 0 GROUP BY defindex ORDER BY AVG(price) DESC
I was studying the SQLite.swift documentation to ind out how to do it properly, but I couldn't find a way. I could call prepare on the database and iterate through the Statement object, but that wouldn't be optimal performance wise.
Any help would be appreciated.
Most sequences in Swift can be unpacked into an array by simply wrapping the sequence itself in an array:
let stmt = db.prepare(
"SELECT defindex, AVG(price) FROM prices " +
"WHERE quality = 5 AND price_index != 0 " +
"GROUP BY defindex " +
"ORDER BY AVG(price) DESC"
)
let rows = Array(stmt)
Building a data source from this should be relatively straightforward at this point.
If you use the type-safe API, it would look like this:
let query = prices.select(defindex, average(price))
.filter(quality == 5 && price_index != 0)
.group(defindex)
.order(average(price).desc)
let rows = Array(query)

Multiple Where Parameters on EntityDataSource?

I have a gridview that uses an entity datasource to populate itself. Depending on what the user has access to see, I want the gridview to implement a where clause. At the lowest level of access, the user can only see themselves. In order to do this I implement the line of code:
EmployeeEntityDataSource.Where = "it.Person_ID = " + selectQuery.ToString()
This successfully reduces the data in the gridview to the one appropriate user. If the user has the next step in access, they should be able to see themselves plus all the employees that work for them. I have sucessfully created a list of employees Person_IDs and I'm trying to filter my gridview so that if the Person_ID column in the gridview matches one of the Person_IDs in my list it should show up.
I have tried the following bits of code:
1.
For Each employeeID In employeeList
If count2 <> count Then
whereString += "it.Person_ID = " + employeeID.ToString() + " OR "
count2 += 1
Else
whereString += "it.Person_ID = " + employeeID.ToString()
End If
Next
EmployeeEntityDataSource.Where = whereString
Essentially thought I could create a giant where statement with a bunch of ORs but this did not work
2.
EmployeeEntityDataSource.WhereParameters.Add(employeeList)
EmployeeEntityDataSource.Where = "it.Person_ID = #employeeList"
The error I get here says a List(of T) cannot be converted WebControl.Parameter
How do I properly create a WHERE statement that will compare the it.Person_ID of the gridview to each element in my list called employeeList?
I think an In statement should accomplish what you need. Something like this -
string employeeIDs = string.Join(",", employeeList.ToList());
EmployeeEntityDataSource.Where = String.Format("it.Person_ID IN ({0})", employeeIDs);
Or you may have to iterate through your list to create the employeeIDs string, depending on the types we're dealing with here.
Apparently I lied When I said my first bit of code did not work. The issue was that I was not generating the massive OR statement correctly.
From what I remember the statement I was originally generating was it.Column = ID1 OR ID2 OR ID3 and so on.
If the statement created is it.Column = ID1 OR it.Column = ID2 OR it.Column = ID3 and so on, this creates a statement that works properly.
The code that is working in my current project is:
For Each employee In employeeList
If count2 <> count Then
whereString += "it.Person_ID = " + employee.ToString() + " OR "
count2 += 1
Else
whereString += "it.Person_ID = " + employee.ToString()
End If
Next
EmployeeEntityDataSource.Where = whereString

Can I inner join two DataTables where tableA.myColumn = tableB.myColumn?

I am parsing an Excel workbook and extracting the data into two DataTables like so:
If SetDBConnect("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & filepath & ";
Extended Properties=""Excel 8.0;HDR=Yes;IMEX=1""", True) Then
'Get total dollars table
sql.Append("SELECT * FROM [" & totalDollars & "]")
dt = _dh.GetTable(sql.ToString())
sql.Length = 0
sql.Append("SELECT * FROM [" & totalUnits & "]")
dt_units = _dh.GetTable(sql.ToString())
End If
The two spreadsheets are exactly the same with one difference. In the "Total Dollars" spreadsheet, there is a column with the dollar amounts, where in the "Total Units" spreadsheets, it is instead a column with unit amounts.
I would like to INNER JOIN these two tables WHEN the tableA.UPC = tableB.UPC. Is this possible? I have read about DataSets and DataRelations, but I was wondering if there was a simpler approach?
Thanks!
A simple approach using Linq would be:
var query = from c in dt.AsEnumerable()
join r in dt_units.AsEnumerable()
on c.Filed<string>("UPC") equals r.Field<string>("UPC")
select new {
UPC= r.Field<string>("UPC"),
//and so on.. you pick whatever columns you need from each table
}
Don't vote this up, but wanted to paste a VB .NET version:
Dim query = From c In dt.AsEnumerable() _
Join r In dt_units.AsEnumerable() _
On c.Field(Of String)("UPC") Equals r.Field(Of String)("UPC") _
Select New With
{
.UPC = r.Field(Of String)("UPC")
}

sqlite - how do I get a one row result back? (luaSQLite3)

How can I get a single row result (e.g. in form of a table/array) back from a sql statement. Using Lua Sqlite (LuaSQLite3). For example this one:
SELECT * FROM sqlite_master WHERE name ='myTable';
So far I note:
using "nrows"/"rows" it gives an iterator back
using "exec" it doesn't seem to give a result back(?)
Specific questions are then:
Q1 - How to get a single row (say first row) result back?
Q2 - How to get row count? (e.g. num_rows_returned = db:XXXX(sql))
In order to get a single row use the db:first_row method. Like so.
row = db:first_row("SELECT `id` FROM `table`")
print(row.id)
In order to get the row count use the SQL COUNT statement. Like so.
row = db:first_row("SELECT COUNT(`id`) AS count FROM `table`")
print(row.count)
EDIT: Ah, sorry for that. Here are some methods that should work.
You can also use db:nrows. Like so.
rows = db:nrows("SELECT `id` FROM `table`")
row = rows[1]
print(row.id)
We can also modify this to get the number of rows.
rows = db:nrows("SELECT COUNT(`id`) AS count FROM `table`")
row = rows[1]
print(row.count)
Here is a demo of getting the returned count:
> require "lsqlite3"
> db = sqlite3.open":memory:"
> db:exec "create table foo (x,y,z);"
> for x in db:urows "select count(*) from foo" do print(x) end
0
> db:exec "insert into foo values (10,11,12);"
> for x in db:urows "select count(*) from foo" do print(x) end
1
>
Just loop over the iterator you get back from the rows or whichever function you use. Except you put a break at the end, so you only iterate once.
Getting the count is all about using SQL. You compute it with the SELECT statement:
SELECT count(*) FROM ...
This will return one row containing a single value: the number of rows in the query.
This is similar to what I'm using in my project and works well for me.
local query = "SELECT content FROM playerData WHERE name = 'myTable' LIMIT 1"
local queryResultTable = {}
local queryFunction = function(userData, numberOfColumns, columnValues, columnTitles)
for i = 1, numberOfColumns do
queryResultTable[columnTitles[i]] = columnValues[i]
end
end
db:exec(query, queryFunction)
for k,v in pairs(queryResultTable) do
print(k,v)
end
You can even concatenate values into the query to place inside a generic method/function.
local query = "SELECT * FROM ZQuestionTable WHERE ConceptNumber = "..conceptNumber.." AND QuestionNumber = "..questionNumber.." LIMIT 1"

Complex Linq Query--Trying to add a .Where() or .Any() predicate to reduce query complexity (in VB)

I'm having issues with a rather complex Linq query and I need some advice. This involves VB syntax so I need specific answers for that platform, as I have a lot of trouble translating the C# syntax to VB at times.
I have to join two main tables, and I need to filter the results by elements in an ASP.NET web form. These filters are created on the fly so I have to use a lot of where extensions to filter the query. I want to execute the query with as optimized SQL as possible.
I am first doing a simple join between TW_Sites and TW_Investigators. Then there are two sub-tables that are involved. TW_InvestigatorToArea and TW_InvestigatorToDisease. While most of the where clauses are working fine, I have found a performance issue that won't be an issue right now, but will be an issue as the table gets bigger.
The arrays DiseaseCategories and DiseaseAreas would be the results of a CheckBoxList result.
Protected Sub LoadResults()
' Get Dictionary of Filters
Dim FilterDictionary As OrderedDictionary = Session.Item("InvestigatorFilterDictionary")
' Initialize LinqToSql
Dim LinqDbHandler As TrialWatchDC = New TrialWatchDC(WebConfigurationManager.ConnectionStrings("DataSourceName").ConnectionString)
' Create List of Categories to Filter By
Dim DiseaseCategories() As Integer = {1, 2, 3, 4, 5, 6, 11, 22, 361, 77, 82, 99, 400}
Dim CategorySubQuery = From ic In LinqDbHandler.TW_InvestigatorsToDiseases Where DiseaseCategories.Contains(ic.DiseaseCategoryID) Select ic.InvestigatorID Distinct
' Dim CategorySubArray = CategorySubQuery.ToArray()
' Create List of Areas to Filter By
Dim AreaCategories() As Integer = {17, 1, 3, 5}
Dim AreaSubQuery = From ic In LinqDbHandler.TW_InvestigatorsToAreas Where AreaCategories.Contains(ic.AreaID) Select ic.InvestigatorID Distinct
Dim AreaSubArray = AreaSubQuery.ToArray()
Dim dc As DbCommand
Dim ThisQuery = From Site In LinqDbHandler.TW_Sites _
Join Investigator In LinqDbHandler.TW_Investigators On Site.TrialSiteID Equals Investigator.TrialSiteID _
Join SiteType In LinqDbHandler.TW_SiteTypes On Site.SiteTypeID Equals SiteType.SiteTypeID _
Order By Site.ResearchCenterName, Investigator.InvestigatorName
Select New With {.TrialSiteID = Site.TrialSiteID, _
.InvestigatorID = Investigator.InvestigatorID, _
.ResearchCenterName = Site.ResearchCenterName, _
.SiteTypeID = SiteType.SiteTypeID, _
.TypeLabel = SiteType.TypeLabel, _
.CenterState = Site.CenterState, _
.CenterCountry = Site.CenterCountry, _
.ContactName = Site.ContactName, _
.ContactEMail = Site.ContactEMail, _
.ContactPhone = Site.ContactPhone, _
.IsRcppSubscriber = Site.IsRcppSubscriber, _
.InvestigatorName = Investigator.InvestigatorName, _
.IsPublicationSubscriber = Investigator.IsPublicationSubscriber, _
.HasPhase01 = Investigator.HasPhase01, _
.HasPhase02 = Investigator.HasPhase02, _
.HasPhase03 = Investigator.HasPhase03, _
.HasPhase04 = Investigator.HasPhase04, _
.AreaList = String.Join(",", (From ia In LinqDbHandler.TW_InvestigatorsToAreas Join a In LinqDbHandler.Disease_Areas On ia.AreaID Equals a.Area_Number Where ia.InvestigatorID = Investigator.InvestigatorID Order By a.Area_Name Select a.Area_Name Distinct).ToArray()), _
.CategoryList = String.Join(",", (From id In LinqDbHandler.TW_InvestigatorsToDiseases Join d In LinqDbHandler.Disease_Categories On id.DiseaseCategoryID Equals d.Category_Number Where id.InvestigatorID = Investigator.InvestigatorID Order By d.Category_Name Select d.Category_Name Distinct).ToArray())}
If Not String.IsNullOrEmpty(FilterDictionary.Item("CountryFilter")) Then
ThisQuery = ThisQuery.Where(Function(s) s.CenterCountry = FilterDictionary.Item("CountryFilter").ToString())
End If
If Not String.IsNullOrEmpty(FilterDictionary.Item("SiteType")) Then
ThisQuery = ThisQuery.Where(Function(s) s.SiteTypeID = Convert.ToInt32(FilterDictionary.Item("SiteType")))
End If
dc = LinqDbHandler.GetCommand(ThisQuery)
If Not String.IsNullOrEmpty(FilterDictionary.Item("StateFilter")) Then
ThisQuery = ThisQuery.Where(Function(s) s.CenterState = FilterDictionary.Item("StateFilter").ToString())
End If
dc = LinqDbHandler.GetCommand(ThisQuery)
ThisQuery = ThisQuery.Where(Function(i) CategorySubArray.Contains(i.InvestigatorID))
ThisQuery = ThisQuery.Where(Function(i) AreaSubArray.Contains(i.InvestigatorID))
dc = LinqDbHandler.GetCommand(ThisQuery)
Trace.Warn("Command", dc.CommandText)
For Each dcp As SqlParameter In dc.Parameters
Trace.Warn(dcp.ParameterName.ToString(), dcp.Value.ToString())
Next
Dim ThisLinqResult = ThisQuery
InvestigatorResultGrid.DataSource = ThisLinqResult
InvestigatorResultGrid.DataBind()
End Sub
The big problem is, when you look at the code, basically I am first converting the filtered subqueries into an array and then passing it into the SQL code. The result ends up making an SQL Query with a lot of parameters, as seen below.
SELECT [t0].[TrialSiteID], [t1].[InvestigatorID], [t0].[ResearchCenterName], [t2].[SiteTypeID], [t2].[TypeLabel], [t0].[CenterState], [t0].[CenterCountry], [t0].[ContactName],
[t0].[ContactEMail], [t0].[ContactPhone], [t0].[IsRcppSubscriber], [t1].[InvestigatorName], [t1].[IsPublicationSubscriber], [t1].[HasPhase01], [t1].[HasPhase02], [t1].[HasPhase03],
[t1].[HasPhase04]
FROM [dbo].[TW_Sites] AS [t0]
INNER JOIN [dbo].[TW_Investigators] AS [t1] ON [t0].[TrialSiteID] = [t1].[TrialSiteID]
INNER JOIN [dbo].[TW_SiteTypes] AS [t2] ON [t0].[SiteTypeID] = ([t2].[SiteTypeID])
WHERE ([t1].[InvestigatorID] IN (#p0, #p1, #p2, #p3, #p4, #p5, #p6, #p7, #p8, #p9, #p10, #p11, #p12, #p13, #p14, #p15, #p16, #p17, #p18, #p19, #p20, #p21, #p22, #p23, #p24, #p25, #p26, #p27,
#p28, #p29, #p30, #p31, #p32, #p33, #p34, #p35, #p36, #p37, #p38, #p39, #p40, #p41, #p42, #p43, #p44, #p45, #p46, #p47, #p48, #p49, #p50, #p51, #p52, #p53, #p54, #p55, #p56, #p57, #p58,
#p59, #p60, #p61, #p62, #p63, #p64, #p65, #p66, #p67, #p68, #p69, #p70, #p71, #p72, #p73, #p74, #p75, #p76, #p77, #p78, #p79, #p80, #p81, #p82, #p83, #p84, #p85, #p86, #p87, #p88, #p89,
#p90, #p91, #p92, #p93, #p94, #p95, #p96, #p97, #p98, #p99, #p100, #p101, #p102, #p103, #p104, #p105, #p106, #p107, #p108, #p109, #p110, #p111, #p112, #p113, #p114, #p115)) AND
([t1].[InvestigatorID] IN (#p116, #p117, #p118, #p119, #p120, #p121, #p122, #p123, #p124, #p125, #p126, #p127, #p128, #p129, #p130, #p131, #p132, #p133, #p134, #p135, #p136, #p137, #p138,
#p139, #p140, #p141, #p142, #p143, #p144, #p145, #p146, #p147, #p148, #p149, #p150, #p151, #p152, #p153, #p154, #p155, #p156, #p157, #p158, #p159, #p160, #p161, #p162, #p163, #p164, #p165,
#p166, #p167, #p168, #p169, #p170, #p171, #p172, #p173, #p174, #p175, #p176, #p177, #p178, #p179, #p180, #p181, #p182, #p183, #p184, #p185, #p186, #p187, #p188, #p189, #p190, #p191, #p192,
#p193, #p194, #p195, #p196, #p197, #p198, #p199, #p200, #p201, #p202, #p203, #p204, #p205))
ORDER BY [t0].[ResearchCenterName], [t1].[InvestigatorName]
This is a lot of parameters and will just get worse. Basically, instead of having a small IN clause with the conditions, I have a much larger IN clause with the investigator ids.
So, what I am trying to do is figure out how to, instead of converting the Area and Category queries into an array and then appending them to the third query, to get the queries to include the sub-tables and directly search for the matching ids of the areas and categories. I need to be able to use the predicate syntax since areas and categories are two sub-tables, and sometimes both or neither will be included. I know it has to do with either the .Any(), .Join(), or .Where() predicates, I just don't know how to get it to work.
Basically, I'm trying to change the SQL to make it look more like this.
WHERE ([t1].[InvestigatorID] IN (SELECT InvestigatorID FROM TW_InvestigatorsToAreas
WHERE DiseaseCategoryID IN (#p101, #p102, #p103)))
Any help or guidance would be appreciated.
Is this LINQ to SQL or EF?
Most ORMs will generate dynamic SQL with each ID for the IN statement as a parameter. Some smarter ones will create a temp table and join against that instead or use a nested subquery (or if you're really creative you might extend an ORM to do this).
I know DataObjects .NET does the temp table thing and LLBLGen can use nested subqueries for joins (aka prefetch pathes) and I'm sure there are at least a couple of others that do too.
One thing to note: Your mileage may vary. One big plus with a temp table is that you get around the 2400 parameter limit in SQL Server (though I'm not sure if that's an issue for you...). However, certain, maybe 1 in 20 queries will actually perform much much slower joining against a temp table (even an indexed one) vs. just passing in each ID as a parameter. Still, in general though, you'll have much better performance because the execution plan doesn't need to get re-compiled for each query.
It looks like it just came down to a syntax statement. I guess you just have to invoke the subquery from the LinqToSql object itself.
If DCHash.Count > 0 Then
ThisQuery = ThisQuery.Where(Function(i) (From ic In LinqDbHandler.TW_InvestigatorsToDiseases Where DiseaseCategories.Contains(ic.DiseaseCategoryID) Select ic.InvestigatorID).Contains(i.InvestigatorID))
End If
If AreaHash.Count > 0 Then
ThisQuery = ThisQuery.Where(Function(i) (From ia In LinqDbHandler.TW_InvestigatorsToAreas Where DiseaseAreas.Contains(ia.AreaID) Select ia.InvestigatorID).Contains(i.InvestigatorID))
End If

Resources