Variant Join in MS Access - sql

I am converting a spreadsheet that had over 80 Sumifs for output.
For a query, I can join 2 tables, but they depend on 6-8 factors that aren't consistent, hence, the sumifs.
I've been successful with right joins in some instances, but most of the time I have to piece meal all of the conditions.
One of my approaches is to write a function like this:
Public Function DetermineCOB_ID(strFund As String, strType As String, strMDEP As String, _
strTier1 As String, strAirGround As Variant, strAcctType As String) As Integer
If strFund = "A82AB" And strType = "Base" And strTier1 = "2 BCT" And strMDEP = "W25D" And strAcctType = "Subordinate_Cmds" Then
DetermineCOB_ID = 1
ElseIf strFund = "A82AC" And strType = "Base" And strMDEP = "W25D" And strAcctType = "Subordinate_Cmds" Then
DetermineCOB_ID = 2
ElseIf strFund = "A82AD" And strType = "Base" And strMDEP = "W25D" And strAirGround = "Ground" And strAcctType = "Subordinate_Cmds" Then
DetermineCOB_ID = 3
Else
DetermineCOB_ID = 0
End If
End Function
But I will have to write 80 separate ElseIf statements.
I'd like to hook up my logic to a control table that the user can change the factors that determine the values.
This would somehow involve a 'variant' join everywhere there is a join where one is not required. I hope I am making sense.
Is there another approach to solving this problem?

Yes, I am working with a back end that leaves a lot to be desired. In the interim, I'm probing for alternate solutions. Do you know a way to make a join respond like a variant variable i.e so it can work with null values. I've tried outer joins but it doesn't really work.

Related

Global Class for SQL enumerated objects

I'm working on a tool crib VB.NET project, my first real one, so I'm struggling with a few things. In my SQL database I have a few tables that translate into enumerated fields. For example I have code and code type tables. I have a code type with CodeTypeID = 2 and description = Tool Status. These are used to track the location of a tool; Shop, In Transit, On Site, Out of Service, etc. I've set up enumerations for some of these.
Enum CodeType
User = 1
ToolStatus = 2
Repair = 3
OutOfService = 4
End Enum
ToolStatus
Shop = 5
Reserved = 6
InTransit = 7
OnSite = 9
ReturnTransit = 10
OutOfService = 11
Repair = 12
End Enum
The problem is if I change a code in SQL I then have to edit my enumerations as well. In the SQL tables I am only storing the CodeID and join to the code table to get the description. Other than an enumeration, I haven't found a good way to load these tables when the project opens that will allow me to code as easily, for example ToolStatus.OnSite to return the number 9 to my SQL table. It just seems inefficient to me. I always try to code my SQL procedures so if something changes I don't have to go and edit a bunch of procedures and would like to do the same here, especially as a simple addition of a new code could force a version update. Is there a better way to do this? I have searched the Internet and haven't found anything that really works as well as enumeration.
Example Code:
In the following code both OnSite and ReturnTransit are enumerations.
I'm moving items between two datagridviews, a Source and a Target DGV. Also updating the underlying shared datatable.
Dim cbo As ComboBox = sender
With cbo
Select Case .Name
Case "cboPeeps"
dvgFilter = "N"
Case "cboToolbox"
For i As Integer = 0 To dtTools.Rows.Count - 1
dtTools.Rows(i)("dgvFilter") = dtTools.Rows(i)("dbFilter")
Next
If cbo.Items.Count > 0 Then
filter = "ToolboxID=" & .SelectedValue.ToString & " And ToolStatus=" & OnSite
filter += " And UserID=" & .SelectedItem("UserID").ToString
End If
dvgFilter = "T"
End Select
End With
End If
Dim result() As DataRow = dtTools.Select(filter)
For i As Integer = 0 To result.Count - 1
result(i)("dgvFilter") = dvgFilter
If result(i)("dgvToolStatus") <> OutOfService Then result(i)("dgvToolStatus") = ReturnTransit
Next
I was, of course, trying to make this way too difficult. Simple solution along these lines.
Public Class Crepair
Public repairID As Integer
Public techID As Integer
Public repairCodeID As Integer
Public acceptedDate As Date
Public remarks As String
Public isComplete As Boolean
End Class
With nRepair
.repairID = row.Cells("RepairID").Value
.techID = row.Cells("TechID").Value
.repairCodeID = row.Cells("RepairCodeID").Value
.acceptedDate = row.Cells("AcceptedDate").Value
.remarks = row.Cells("Remarks").Value
.isComplete = row.Cells("IsComplete").Value
End With

Managing Blank field from Linq Query

I am writing a method in VB.Net that runs a LINQ query on my database, and puts the information from the query into textboxes on a form.
Public Sub OpenPartWindow(ByVal partNumber As String)
Using dbContext As New DB_LINQDataContext
Dim query = (From p In dbContext.Parts
Join ppl In dbContext.Part_Price_Logs On p.Part_ID Equals ppl.Part_ID
Where p.Part_Number = partNumber
Select p.Part_Number, p.Part_Description, p.Part_Information, p.Supplier.Supplier_Name, _
p.Part_Manufacturer.Manufacturer_Name, p.Part_Subcategory.Part_Category.Category_Description, _
p.Part_Subcategory.Subcategory_Description, ppl.Cost_Per_Unit, ppl.Discount_Percentage).First()
MessageBox.Show(query.ToString())
txtPartNum.Text = query.Part_Number.ToString()
txtSupplier.Text = query.Supplier_Name.ToString()
txtManufacturer.Text = query.Manufacturer_Name.ToString()
txtPrice.Text = query.Cost_Per_Unit.ToString()
txtDiscount.Text = query.Discount_Percentage.ToString()
txtDescription.Text = query.Part_Description.ToString()
txtInfo.Text = query.Part_Information.ToString()
Me.Show()
End Using
End Sub
The issue I am having right now is with the last field, the txtInfo TextBox. You see the Part_Information field on the database allows NULL values. So when I go to fill the field when the field is null I am getting a NullReferenceException, which is understandable. However I cannot find a way to get around this exception.
I've tried:
If Not IsNothing(query._Part_Information.ToString()) Then
As well as
If query.Part_Information.Length > 0 Then
As If statements to run through first. But I keep getting the error each time. So I am confused on how I am suppose to deal with this error.
You can use either of the following options:
txtInfo.Text = String.Format("{0}", query.Part_Information)
txtInfo.Text = $"{query.Part_Information}" → $ - String Interpolation
txtInfo.Text = query.Part_Information?.ToString() → ?. - Null Conditional Operator
If query.Part_Information is null, the first two expressions result in Sting.Empty and the last one result in Nothing.

Variable that depends on another variable VBA

I have an interesting question about referencing another variable based on another variable in an array.
Below is my code:
Dim company, price, sdev, mean, random
Dim companies
companies = Array("mm", "tgt", "boog")
mm_price = 0
mm_mean = 0
mm_sdev = 0
tgt_price = 0
tgt_mean = 0
tgt_sdev = 0
boog_price = 0
boog_mean = 0
boog_sdev = 0
For i = 1 To 3
company = companies(i)
mean = company & "_mean"
sdev = company & "_sdev"
Next i
Now, the issue occurs when I attempt to define the "mean" and "sdev" variables, as they will not use the "0" value, but instead give it the string name "mm_mean" etc. mm_mean = 0, therefore, I want mean = 0 when i = 1. Clear?
Thanks, and let me know. It is a rather strange question, and the code is cut from many different functions, so if it doesn't make sense as to why I am doing this, my apologies. I tried to make it as simple as possible so it wouldn't confuse the answerer.
This is a good example of when custom data-structures (aka "record types", "structs") should be used to group related data together. In VBA the syntax is Type:
Type Company
Name As String
Price As Currency
Mean As Double
SDev As Double
End Type
Public Sub CalculateCompanyInfo()
Dim companies(3) As Company
companies(0).Name = "mm"
companies(0).Price = 123
companies(1).Name = "tgt"
companies(1).Price = 456
companies(2).Name = "boog"
companies(2).Price = 789
For i As Integer = 0 to UBound(companies)
companies(i).Mean = ...
companies(i).SDev = ...
Next i
End Sub
Where ... means whatever custom calculation you need to do to get that value.

Poker Hand evaluation through LINQ

I am creating a poker game - Texas Holdem (5 cards on the table and 2 cards for myself).
I've already created flush, straight and straight flush functions and I got stuck on evaluating if the hand has a:
1. Four of a kind
2. Three of a kind
3. Full house
4. Two pairs
5. One pair
I believe I can write one function for all of the above, that will return a corresponding string.
I have created a list that holds list of Cards (7 cards)
Class Card has a property cardNumber of Integer type (Ace = 1, Two = 2, Three = 3 etc)
Here is my function:
Public Shared Function ofAKind(hand As List(Of Card)) As String
Dim result As String = ""
Dim counter As Integer
Dim IntegerList As New List(Of Integer)
'creating a list of integers that are representing faces of cards
Do
IntegerList.Add(hand.Item(counter).cardNumber)
counter += 1
Loop Until counter = hand.Count
Dim groupedIntegers = From Int In IntegerList
Group By Int
Into grouping = Group, Count()
'and here is my problem: how can I make such a grouping? below is just pseudocode.
'When using a debugger, I see that it groups them well. It is just that I do not know
'how to use LINQ to extract that grouping into the below if statement and get a corresponding string.
'if grouping = 4 Then
'result = "Four of a kind"
'if grouping = 3 andAlso grouping = 2 Then
'result = "Full House"
'if grouping = 2 andAlso grouping = 2 Then
'result = "Two Pairs"
'if grouping = 2 Then
'result = "Pair"
Return result
End Function
For the lack of being able to comment.
Possibly String.Concat all of the card Values together (with whitespace in-between each) and use a Regex.Matches(...) with match code "\d" to match the Numbers
Then Array.ForEach(...) for the Groups() with an in-line If[...] to count the occurrences in each group and test if it has particular combinations of matches.
It may be a little tedious, and a long in-line Linq, but just a thought :p
I figured it out. I am sure it can be done in a cleaner way, but it worked for me. At this phase of my programming discovery - this is a next milestone achieved. Thanks to Plutonix. Appreciate it.
Public Function ofAKind(IntegerList As List(Of Integer)) As String
Dim result As String = "YES"
Dim groupedIntegerList As New List(Of Integer)
Dim groupedIntegers = From Int In IntegerList
Group By Int
Into LOL = Group, Count()
'creating another list (I am sure there is a cleaner way, but I don't know it yet)
For Each e In groupedIntegers
groupedIntegerList.Add(e.Count)
Next
If groupedIntegerList.Contains(3) And groupedIntegerList.Contains(2) Then
result = "Fullhouse!"
ElseIf groupedIntegerList.Contains(4) Then
result = "Four of a kind!"
ElseIf groupedIntegerList.Contains(3) Then
result = "Three of a kind"
ElseIf groupedIntegerList.Contains(2) Then
result = "Pair!"
End If
'ugly way to search for two pairs (but it works)
If result = "Pair!" Then
Dim searchingForTwoPairs = From int In groupedIntegerList
Where int > 1
Group By int
Into LOL2 = Group, Count()
Dim twoPairsList As New List(Of Integer)
For Each e In searchingForTwoPairs
twoPairsList.Add(e.Count)
Next
If twoPairsList.Contains(2) Or twoPairsList.Contains(3) Then
result = "Two pairs!"
End If
End If
Return result
End Function

LINQ Join between datatables, two untyped fields

I'm querying two databases and trying to join the result sets and query out of them using LINQ. It seems it would be an easy task, but without doing an explicit join I'm having major performance issues. When I do the explicit join, I am having trouble with VB syntax for making things explicit types. Working Code, Cleaned:
For Each CurrRow In ResultsA.Tables(15).Rows
CurrDate = CurrRow("Date")
CurrID = CurrRow("ID")
CurrVal = CurrRow("Val")
Dim ResultsB = From SMW In DataSetA.Tables(0).AsEnumerable() _
Where SMW("ID") = CurrScheduleID And SMW("Time") = CurrProfileDate _
Select UTC_TS = SMW("Time"), Value = (SMW("VALUE") / 1000), Time_Zone = SMW("Time_Zone"), ID = SMW("ID")
Dim CurrentResult As Object
Dim boolSchedDateFound As Boolean = False
For Each CurrentResult In ResultsB
If CurrentResult.Value <> CurrVal Then
'LogIntegrityCheckErrorRow()
End If
boolSchedDateFound = True
Next
Next
This takes FOREVER to run with 100,000 rows.
I've been trying to rewrite this as:
Dim MismatchRows = From TableAData In DataSetA.Tables(0).AsEnumerable() Join TableBData In DataSetB.Tables(15).AsEnumerable() _
On New With {.TableAID = Convert.ToInt32(TableAData("ID")), .TableATime = Convert.ToDateTime(TableAData("Date"))} _
Equals New With {.TableBDID = Convert.ToInt32(TableBData("ID")), .TableBTime = Convert.ToDateTime(TableBData("Time"))} _
Select .................. (Hard to clean up, but this isn't the part that's failing)
And I'm having a bear of a time with it. The fundamental problem is the lack of strong typing. I've looked, but there seems to be little advice because most people doing this build EF on the data. Which isn't a terrible idea, but would require a bunch of re-engineering. So. Problem in front of me, how do I remove the error:
'Equals' cannot compare a value of type '<anonymous type> (line 2641)' with a value of type '<anonymous type> (line 2642)'.
Thank you so much for your help.
Have you tried this?
Dim MismatchRows = From TableAData In ei _
Join TableBData In e2 On _
TableAData("ID") Equals TableBData("ID") And TableAData("Data") Equals TableBData("Time")
Select .......
db.tb_DeviceGeFenceDetail.Join(db.tb_InventoryLog, Function(gfd) gfd.DeviceID, Function(il) il.deviceId, Function(gfd, il) New From { _
gfd.GeFenceLat1, _
gfd.GeFenceLng1, _
gfd.GeFenceLat2, _
gfd.GeFenceLng2, _
il.deviceName, _
il.DeviceIcon, _
gfd.DeviceID, _
il.id _
}).ToList().Where(Function(y) intValues.Contains(y.id))
you can try joining tables something like this.