Search code examples
sqlms-accessmultivalue

MS Access extracting elements from multi-valued field based on condition


I get a report where there is a multi-valued field that houses user roles and the respective user information. There are a total of 6 roles and each row of data could have multiple people operating under the same role. I am using MS Access 2013 to do my data manipulation.

ID  Data    Users
1   Data1   Supervisor (MICROSOFT OUTLOOK; [email protected] 9999999999) Admin Assistant (WATER BOTTLE; [email protected], 9999999999) Analyst (GREEN BLUE; [email protected]; 999999999)
2   Data2   Supervisor (COMPUTER MONITOR; [email protected]; 9999999999) Admin Assistant (MICROSOFT EXCEL; [email protected], 9999999999) Analyst (GREEN BLUE; [email protected]; 999999999); Analyst (ORANGE PURPLE; [email protected]; 999999991)
3   Data3   Supervisor (GREEN BLUE; [email protected]; 9999999999) Admin (MICROSOFT ACCESS; [email protected], 9999999999) Analyst (ORANGE PURPLE; [email protected]; 999999999); Analyst (YELLOW BLACK; [email protected]; 999999991)

The above is a truncated and substituted data set. In ID = 2 and 3, there are 2 analysts. There could be a case where there are 2 "Admin Assistants". The formatting for the Users is exactly as listed. Individual users could be listed across multiple rows as well and under different roles sometimes.

I don't necessarily need to split the data apart, but I do need pick out certain roles based on the Data column. If Data = [Certain Condition], then pull in a certain user role. For example, if Data = "Completed", I need to pull all the "Supervisors" for that row. If Data = "In progress", I need to pull all the "Analysts" for that row. There are other conditionals too for determining which role and users to pull. I need to pull both the user role and the users associated with that role for that row. I would like to create 2 new columns for "Ownership Role" and "Current Ownership". "Ownership Role" is the User Role and "Current Ownership" should contain all the users associated with that role for that row.

Please let me know if you have any questions or need any clarification. I appreciate you taking the time to read this.

UPDATE

My desired results are below.

ID  Data    Ownership Role  Current Ownership   Users
1   Completed   Supervisor  MICROSOFT OUTLOOK   Supervisor (MICROSOFT OUTLOOK; [email protected] 9999999999) Admin Assistant (WATER BOTTLE; [email protected], 9999999999) Analyst (GREEN BLUE; [email protected]; 999999999)
2   In Progress Analyst GREEN BLUE, ORANGE PURPLE   Supervisor (COMPUTER MONITOR; [email protected]; 9999999999) Admin Assistant (MICROSOFT EXCEL; [email protected], 9999999999) Analyst (GREEN BLUE; [email protected]; 999999999); Analyst (ORANGE PURPLE; [email protected]; 999999991)
3   Initiated   Admin   MICROSOFT ACCESS    Supervisor (GREEN BLUE; [email protected]; 9999999999) Admin (MICROSOFT ACCESS; [email protected], 9999999999) Analyst (ORANGE PURPLE; [email protected]; 999999999); Analyst (YELLOW BLACK; [email protected]; 999999991)

UPDATE 2019-05-10 Due to my failure to properly explain the question and set up a sample data set, I am posting the cases based on June7's answer and a sample row of data.

Case "Initiated"
    strRole = "Main Admin Assistant"
Case "Drafted"
    strRole = "Financial Analyst"
Case "Rated"
    strRole = "Contractor Rep"
Case "Reviewed"
    strRole = "Assessing Official"
Case "Finalized"
    strRole = "Reviewing Official"

Sample Data - this is all in 1 cell in Excel and each element is on a different line in that cell. Immediately after the close parenthesis, there is NO space from what I can tell so the next user role begins IMMEDIATELY.

Supervisor (ERGO KB; [email protected]; (999) 999-9999)Team Lead (WIDE SCREEN; [email protected]; 9999999999)Team Rep (CELL PHONE; [email protected]; 999-999-9999)Team Rep (CLICK PEN; [email protected]; (999) 999-9999)Main Admin Assistant (WIRED MOUSE; [email protected]; 999-999-9999)Main Admin Assistant (PHONE CHARGER; [email protected]; 9999999999)Financial Analyst (WATER BOTTLE; [email protected]; (999) 999-9999)Financial Analyst (CLEAR TAPE; [email protected]; 999-999-9999)Human Resources (POST IT NOTE; [email protected]; 999-999-9999)

For each status below, I want the associated User Role.

Status      User Role
Initiated   Main Admin Assistant
Drafted     Financial Analyst
Rated       Team Rep
Reviewed    Financial Analyst
Finalized   Human Resources
Completed   Completed

Real Desired Results

Status      User Role               Users
Initiated   Main Admin Assistant    WIRED MOUSE, PHONE CHARGER
Drafted     Financial Analyst       WATER BOTTLE, CLEAR TAPE
Rated       Team Rep                CELL PHONE, CLICK PEN
Reviewed    Financial Analyst       WATER BOTTLE, CLEAR TAPE
Finalized   Human Resources         POST IT NOTE
Completed   Completed               Completed

Solution

  • Consistency in structure is critical when parsing strings. For instance, there is a semi-colon after ) between the last two elements of IDs 2 and 3 but no semi-colon after the others. That extra semi-colon complicates programming logic. Since comments say that semi-colon is a typo as well as no space following ), code reflects those corrections in structure.

    Here is a function to get you started. Place this procedure in a general module and it can be called from query or textbox.

    Function GetUsers(strData As String, strUsers As String) As String
    Dim aryS As Variant, x As Integer, strRole As String, strNames As String
    aryS = Split(strUsers, ")")
    Select Case strData
        Case "Initiated"
            strRole = "Main Admin Assistant"
        Case "Drafted"
            strRole = "Financial Analyst"
        Case "Rated"
            strRole = "Team Rep"
        Case "Reviewed"
            strRole = "Financial Analyst"
        Case "Finalized"
            strRole = "Human Resources"
    End Select
    For x = 0 To UBound(aryS) - 1
        If strRole = Left(aryS(x), InStr(aryS(x), "(") - 2) Then
            strNames = strNames & Mid(aryS(x), InStr(aryS(x), "(") + 1, InStr(aryS(x), ";") - 1 - InStr(aryS(x), "(")) & ", "
        End If
    Next
    If strNames <> "" Then GetUsers = Left(strNames, Len(strNames) - 2)
    End Function
    

    Instead of determining Role by calculation with Data, suggest a table that defines these associations. Include that table in query then pass the Role to function instead of Data and the Case block should not be needed.

    Revised code to deal with inconsistent phone number structure that sometimes has parens causing previous code to fail as well as the possibility of similar role names (I probably should have gone this way to begin with):

    Function GetUsers(strData As String, strUsers As String) As String
    Dim strRole As String, strNames As String
    Select Case strData
        Case "Initiated"
            strRole = "Main Admin Assistant ("
        Case "Drafted"
            strRole = "Financial Analyst ("
        Case "Rated"
            strRole = "Team Rep ("
        Case "Reviewed"
            strRole = "Financial Analyst ("
        Case "Finalized"
            strRole = "Human Resources ("
        Case "Completed"
            strRole = "Financial Analyst Jr ("
    End Select
    Do While InStr(strUsers, strRole) > 0
        strUsers = Mid(strUsers, InStr(strUsers, strRole))
        strNames = strNames & Mid(strUsers, InStr(strUsers, "(") + 1, InStr(strUsers, ";") - Len(strRole) - 1) & ", "
        strUsers = Mid(strUsers, 2)
    Loop
    If strNames <> "" Then GetUsers = Left(strNames, Len(strNames) - 2)
    End Function