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

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")
}

Related

Join two elements of one list to be in one index

I have a string which I formatted and then I split it using | character. Then the data between each |I am inserting into a list each with a unique index. Now I am trying to join two elements in that list so that they can be in one index.
Example
`List FruitSalad
fruit.add("Apple")
fruit.add("Orange")
fruit.add("Tomatoes")
fruit.add("bananas")
fruit.add("Cucumber")
TextBox1.Text = fruit(0)
TextBox2.Text = fruit(1)
TextBox3.Text = fruit(3)
Typically Apple would have index(0) and Orange and bananas would have the index(1) and index(2) respectively. The thing is I want to join or merge index(2) with index(1) so that both elements would be merged in one index. e.g. index(1) has Apple and Orange.
How could I write it in terms of assigning it to a TextBox.Text, what would be the correct format for TextBox.Text = fruit(?). I tried fruit.Join(2)(1) and String.Join(result(2)(1).ToArray) but that didn't work. Any suggestions? Regards.
Why not concatenate the two
TextBox1.Text = fruits(1) & " and " & fruits(2)
or
TextBox1.Text = String.Format("{0} and {1}", fruits(1), fruits(2))

VB.NET Date Comparison Not Returning Correct Results?

I am pulling a date value from my database:
Dim qfresho = From p In dbConfig.Configs _
Where p.Description = "FROD" _
Select p.dateValue
Dim qfreshc = From p In dbConfig.Configs _
Where p.Description = "FRCD" _
Select p.dateValue
Then comparing these date values to the current date:
If qfresho.First.Value >= Date.Now And qfreshc.First.Value <= Date.Now Then
lblFreshman.Text = "Freshmen are currently eligible to register for a room."
Else
Dim frdays As TimeSpan
frdays = (qfresho.First.Value).Subtract(Now)
lblFreshman.Text = "Registration will open for freshmen in " & frdays.Days & " days."
End If
But for some reason its always returning the Else condition - even though the values in the database should make the query true. Any ideas? I'm guessing for some reason its not pulling the results as a date?
Date.Now returns a DateTime, so does your database have dates and times or just dates? If you just want the date, you can use Date.Today.
Do the dates have time components that could be throwing off the compares?
Why not just add two debugs before the comparison???
Debug.WriteLine(qfresho.First.Value.ToString("MM/dd/yyyy hh:mm:ss.ffff"))
Debug.WriteLine(qfreshc.First.Value.ToString("MM/dd/yyyy hh:mm:ss.ffff"))
That should help.

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

Linq to SQL: Group By and Sum()

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.

Index of the current DataRow in a DataTable

For Each dr As myDAL.UsersRow In data
str.AppendLine(dr.UserName)
Next
In the above code, I also need to include the row index so that it's something like
str.AppendLine(dr.IndexNumber & " " & dr.UserName)
How can I achieve this?
P.S. data is not a DataTable but a generic list of myDAL.UsersRow
If data is a List<myDAL.UsersRow> as you suggest, you can use a "for" loop rather than a "for each" loop:
for i = 0 to data.Count - 1
str.AppendLine(i & " " & data[i].UserName)
next
If, however, you're implying that your "data" list is not in the same order as the original DataTable's rows, you might be able to use the DataRowCollection.IndexOf method to locate the row in the original table:
for each dr as myDAL.UsersRow in data
str.AppendLine(dr.Table.Rows.IndexOf(dr) & " " & dr.UserName)
next
Declare a counter variable before the ForEach loop, and increment it inside it.
Dim counter As Integer = 0
For Each dr As myDAL.UsersRow In data
counter = counter + 1
str.AppendLine(counter.ToString() & " " & dr.UserName)
Next

Resources