3
\$\begingroup\$

I spent an hour or so this morning compiling this, and since I have started reading Clean Code and The Pragmatic Programmer I figured I would let you help me get slightly better at this.

Due to some crappy limitations with the specifics I was forced to work in Excel VBA instead of Access (someone doesn't want to build tables for the two lists in the Excel sheet).

The code pulls a list of defects from a production table, checks a master list to see if it ever existed, then checks an open list to see if it's current and updates the table accordingly. This could be super easy and potentially 100% automated if they would make tables for the two lists. The log of what was found per defect# (writing to sheet) is something I added just in case they want a log.

Private Sub thisbetheshitmane()
 Dim db As DAO.Database
 Dim rst As DAO.Recordset
 Dim vAr As String
 Dim i As Integer
 Dim y As Integer
 Dim InCombined As Boolean
 Dim InOpen As Boolean
 Set db = DBEngine.OpenDatabase("C:\Users\dzcoats\Documents\Microsoft.accdb")
 Set rst = db.OpenRecordset("SELECT DISTINCT [VDefects].Defect FROM [VDefects] WHERE [VDefects].Defect IS NOT NULL;")
 Dim QResult() As Variant
 QResult = rst.GetRows(rst.RecordCount)
 For a = LBound(QResult, 2) To UBound(QResult, 2)
 vAr = QResult(0, a)
 Debug.Print ; vAr
 Next a
 Dim CombinedList() As Variant
 CombinedList = Application.Transpose(Worksheets(1).Range("b2:b2000").Value)
 Dim OpenList() As Variant
 OpenList = Application.Transpose(Worksheets(1).Range("a2:a2000").Value)
 For y = LBound(QResult, 2) To UBound(QResult, 2)
 vAr = Trim(QResult(0, y))
 InCombined = False
 For a = LBound(CombinedList) To UBound(CombinedList)
 If vAr = CombinedList(a) Then InCombined = True
 Next a
 InOpen = False
 For a = LBound(OpenList) To UBound(OpenList)
 If vAr = OpenList(a) Then InOpen = True
 Next a
 If vAr <> "Defect" And vAr <> vbNullString And vAr <> "" Then
 If InCombined = False And InOpen = False Then
 set rst = db.OpenRecordSet ("UPDATE [VDefects] SET [VDefects].Status ='Bad Defect Number' WHERE ((([VDefect].Defect)='"& vAr &"'));")
 Debug.Print "BAD "; vAr
 ThisWorkbook.Sheets("Sheet2").Cells(Sheet2.Rows.Count, 1).End(xlUp).Offset(1, 0).Value = "Bad"
 ThisWorkbook.Sheets("Sheet2").Cells(Sheet2.Rows.Count, 1).End(xlUp).Offset(0, 1).Value = vAr
 End If
 If InCombined = True And InOpen = False Then
 set rst = db.OpenRecordSet ("UPDATE [VDefects] SET [VDefects].Status ='Completed' WHERE ((([VDefects].Defect)='"& vAr &"'));")
 Debug.Print "CLOSED "; vAr
 ThisWorkbook.Sheets("Sheet2").Cells(Sheet2.Rows.Count, 1).End(xlUp).Offset(1, 0).Value = "Closed"
 ThisWorkbook.Sheets("Sheet2").Cells(Sheet2.Rows.Count, 1).End(xlUp).Offset(0, 1).Value = vAr
 End If
 If InCombined = True And InOpen = True Then
 Debug.Print "OPEN "; vAr
 ThisWorkbook.Sheets("Sheet2").Cells(Sheet2.Rows.Count, 1).End(xlUp).Offset(1, 0).Value = "Open"
 ThisWorkbook.Sheets("Sheet2").Cells(Sheet2.Rows.Count, 1).End(xlUp).Offset(0, 1).Value = vAr
 End If
 End If
 Next y
 rst.Close
 Set rs = Nothing
 db.Close
 Set db = Nothing
End Sub
Jamal
35.2k13 gold badges134 silver badges238 bronze badges
asked Sep 11, 2016 at 0:01
\$\endgroup\$
1
  • \$\begingroup\$ I updated my answer to show how you can use the values in your Open and Combined lists in the query. In this way, the query will do all the work. \$\endgroup\$ Commented Sep 14, 2016 at 11:35

2 Answers 2

1
\$\begingroup\$

Here is the code refined using these features:

  • rst.Filter
  • rst.Update
  • Scripting.Dictionary
  • Range("A1").CopyFromRecordset rst

Sub ThisBeTheShitMane()
 Const DBPath = "C:\Users\dzcoats\Documents\Microsoft.accdb"
 Const DebugMode As Boolean = False
 Dim db As DAO.Database
 Dim rst As DAO.Recordset
 Dim key As String
 Dim vAr
 Dim d As Object: Set d = CreateObject("Scripting.Dictionary")
 Set db = DBEngine.OpenDatabase(DBPath)
 Set rst = db.OpenRecordSet("SELECT [VDefects].Defect, [VDefects].Status FROM [VDefects] WHERE [VDefects].Defect IS NOT NULL;")
 'Combined List
 With Worksheets(1)
 For Each vAr In .Range("B2", .Range("B" & .Rows.Count).End(xlUp)).Value
 key = vAr
 d(key) = "Completed"
 Next
 End With
 'Open List
 With Worksheets(1)
 For Each vAr In .Range("A2", .Range("A" & .Rows.Count).End(xlUp)).Value
 key = vAr
 If d.Exists(key) Then
 d(key) = "OPEN"
 Else
 If DebugMode Then Debug.Print "vAr: "; vAr, "ID is in the Open List but is missing from the Combined List "
 End If
 Next
 End With
 With rst
 .MoveFirst
 Do Until .EOF
 key = ![Defect]
 .Edit
 ![Status] = IIf(d.Exists(key), d(key), "Bad Defect Number")
 .Update
 .MoveNext
 Loop
 .MoveFirst
 End With
 Worksheets("Sheet2").Range("A1").CopyFromRecordset rst
 rst.Close
 Set rst = Nothing
 db.Close
 Set db = Nothing
End Sub

But we could just let the database do the work for us by converting the Open and Combined list into a comma separated values list and using IN() to check the values. If [Defect] is a text field you will has to wrap the values in quotes.

Sample Query:

UPDATE VDefects SET VDefects.Status = IIf([VDefects]![Defect] NOT IN (1,2,3,4,5,6) And [VDefects]![Defect] NOT IN (4,5,6,7,8,9),'Bad Defect Number',IIf([VDefects]![Defect] NOT IN (1,2,3,4,5,6),'Completed','OPEN'));

Sub JustDoIt()
 Const DBPath = "C:\Users\best buy\Desktop\Microsoft.accdb"
 Dim db As DAO.Database: Set db = DBEngine.OpenDatabase(DBPath, , True)
 Dim rst As DAO.Recordset
 Dim sSQL As String, t1 As String, t2 As String
 Dim arr1 As Variant, arr2 As Variant
 With Sheet1
 t1 = getValueList(.Range("A2", .Range("A" & rows.Count).End(xlUp)), False)
 t2 = getValueList(.Range("B2", .Range("B" & rows.Count).End(xlUp)), False)
 End With
 sSQL = "UPDATE VDefects SET VDefects.Status = IIf([VDefects]![Defect] NOT IN (" & t1 & ") And [VDefects]![Defect] NOT IN (" & t2 & "),'Bad Defect Number',IIf([VDefects]![Defect] NOT IN (" & t1 & "),'Completed','OPEN'));"
 db.Execute sSQL
 Set rst = db.OpenRecordSet("SELECT [VDefects].Defect, [VDefects].Status FROM [VDefects] WHERE [VDefects].Defect IS NOT NULL;")
 Worksheets("Sheet2").Range("A1").CopyFromRecordset rst
 rst.Close
 Set rst = Nothing
 db.Close
 Set db = Nothing
End Sub
Function getValueList(Target As Range, WrapInQuotes) As String
 Dim arr As Variant
 arr = Application.TRanspose(Target.Value)
 If WrapInQuotes Then
 getValueList = Join(arr, """,""") & """"
 Else
 getValueList = Join(arr, ",")
 End If
End Function

answered Sep 12, 2016 at 9:20
\$\endgroup\$
0
\$\begingroup\$

I also added this to help with in the event non numerics are falsley entered in the UI that inputs data into the DB (again another reason why I wish they'd implement new tables and better db design lol)

 If Not IsNumeric(vAr) Then
 InCombined = True
 InOpen = True
 Else
 InCombined = IsError(Application.Match(CLng(vAr), vArray, 0))
 InOpen = IsError(Application.Match(CLng(vAr), vArray2, 0))
 End If

after some prelim testing- this removes the need for either loop seeing in how everything is a number but stored into the table as text (eye roll)

answered Sep 11, 2016 at 19:18
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.