Вычисление новых ячеек, содержащих значения True / False, из ячеек, также содержащих значения # N / A, с использованием VBA - PullRequest
0 голосов
/ 03 октября 2018

На рабочем листе Excel есть заголовок в первой строке и заголовки каждого столбца во второй строке.Столбцы с заголовками ' A ' и ' B ' содержат исходные данные, а столбец с заголовком ' TF ' будет содержать результирующие данные (столбцы Excel A , B и C соответственно).
В следующем коде цифры от 1 до 5 слева - это просто заголовки строк и не данные на листе.

1  Table
2  A    B   TF
3  ABC  ABC TRUE
4  ABC  BAC FALSE
5  #N/A ABC #N/A

То, что я пробовал.

Sub Compare2Col()
Dim colAnum As Integer, colBnum As Integer, loopNum As Integer, i As Integer
    Dim holder As Variant
colAnum = Worksheets("Sheet1").Range("A1048576").End(xlUp).Row
colBnum = Worksheets("Sheet1").Range("B1048576").End(xlUp).Row
If colAnum > colBnum Then
    loopNum = colAnum
Else
    loopNum = colBnum
End If
For i = 3 To loopNum
If Range("A" & i).Value = "" Or Range("B" & i).Value = "" Or Range("A" & i).Value = "#N/A" Or Range("B" & i).Value = "#N/A" Then
        Range("C" & i).Value = "#N/A"
Else
    If Range("A" & i).Value = Range("B" & i).Value Then
        Range("C" & i).Value = True
    Else
        Range("C" & i).Value = False
    End If
End If
Next i

End Sub

Это код, с которым я пытаюсь работать в настоящее время.В некоторых ячейках у меня будут эти значения "# N / A".Как мне получить оператор if, чтобы, когда оно истинно, оно просто помещало то же значение "# N / A" в третий столбец.

Я прочитал, что эти значения # N / A являются ошибками.Поэтому в VBA я поместил значение # N / A в переменную следующим образом:

holder = Range("A" & 5).Value

Результатом переменной 'holder' было ' Ошибка 2042 '.

Заранее спасибо.Очень ценю любую помощь!

Ответы [ 3 ]

0 голосов
/ 04 октября 2018

Попробуйте использовать IsEmpty и IsError

    For i = 1 To loopNum
    If IsEmpty(Range("A" & i)) Or IsEmpty(Range("B" & i)) Or IsError(Range("A" & i)) Or IsError(Range("B" & i)) Then
            Range("C" & i).Value = "#N/A"
    Else
        If Range("A" & i).Value = Range("B" & i).Value Then
            Range("C" & i).Value = True
        Else
            Range("C" & i).Value = False
        End If
    End If
    Next i
0 голосов
/ 05 октября 2018

Успешная обработка печально известных ошибок VBA (2042)!?

Перед использованием этого кода убедитесь, что вы тщательно изучили хотя бы раздел настройки, иначе вы можете потерять данные.
Самое главное, второй столбец долженвсегда находиться рядом с правой частью первого столбца, иначе этот код нельзя было бы сделать с помощью «версии для копирования и вставки массива».
@Melbee: я предполагаю, что у вас есть исходные данные в столбцах A ciFirstColи B iSecondCol = ciFirstCol + 1, и результат должен быть в столбце C cCOff 'if 1 then first column next to the second column.Если нет, внесите изменения в разделе настройки.

Option Explicit
'-------------------------------------------------------------------------------
Sub XthColumnResult()
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'Description
  'In an Excel worksheet uses two adjacent columns of initial data as arguments
  'for a function whose result is pasted into a third column anywhere to the
  'right of the two initial columns.
  '(In short: 2 cols of data, perform calculation, result in third column)
'Arguments as constants
  'cWbName
    'The path of the workbook, if "" then ActiveWorkbook
  'cWsName
    'Name of the worksheet, if "" then ActiveSheet
  'cloFirstRow
    'First row of data
  'ciFirstCol
    'First column of data
  'cCOff
    'Column offset, where to paste the results into.
'Returns
  'The resulting data in a new column to the right of the two initial adjacent
  'columns of data.

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'-- CUSTOMIZE BEGIN --------------------
  Const cWbName As String = "" 'Workbook Path (e.g. "C:\MyExcelVBA\Data.xls")
  Const cWsName As String = "" 'Worksheet Name (e.g. "Sheet1", "Data",... etc.
  Const cloFirstRow As Long = 3 'First Row of Data

  'Const cloLastRow as Long = Unknown >therefore> Dim loRow as Long

  Const ciFirstCol As Integer = 1 'First Column of Data (1 for A, 2 for B etc.

  'Second column of data must be adjacent to the right of first column.
  'See iSecondCol. Therefore Dim iSecondCol As Integer

  'Column offset where to paste the results into. Default is 1 i.e. the first
  'column next to the second column.
  Const cCOff As Integer = 1
'-- CUSTOMIZE END ----------------------

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  'Variables
  Const cStrVBAError As String = "Error 20" 'Debug VBA Error Variable
  Const cStrVBAErrorMessage As String = "Not Possible." 'Debug VBA Error Message
  Dim oWb As Workbook
  Dim oWs As Worksheet
  Dim oRng As Range
  Dim TheArray() As Variant
  Dim SmallArray() As Variant
  Dim loRow As Long 'Last Row of Data
  Dim iSecondCol As Integer 'Second Column of Data
  Dim iF1 As Integer 'Column Counter
  Dim loArr As Long 'Array Row Counter
  Dim iArr As Integer 'Array Column Counter
  Dim str1 As String 'Debug String
  Dim str2 As String 'Debug Helper String
  Dim varArr As Variant 'Helper Variable for the Array

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  'Determine workbook and worksheet
  If cWbName = "" Then
    Set oWb = ActiveWorkbook
   Else
    Set oWb = Workbooks(cWbName)
  End If
  If cWsName = "" Then
    Set oWs = oWb.ActiveSheet
   Else
    Set oWs = oWb.Worksheets(cWsName)
  End If

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  'Calculate second column of data
  iSecondCol = ciFirstCol + 1
  'Calculate last row of data (the greatest row of all columns)
  loRow = 0
  'Trying to translate the code to English:
  'For each column go to the last cell and press crtl+up which is the last
  'cell used in that column and use the row property...
  For iF1 = ciFirstCol To iSecondCol
    '...and check if it is greater than loRow.
    If loRow < oWs.Cells(Rows.Count, ciFirstCol + iF1 - 1).End(xlUp).Row Then
      'Assign the row to loRow (if it is greater than loRow).
      loRow = oWs.Cells(Rows.Count, ciFirstCol + iF1 - 1).End(xlUp).Row
    End If
  Next

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  'Status
    'The last row of data has been calculated. Additionally the first row, the
    'first column and the second column will be the arguments of the following
    'range (to be assigned to an array).
  'Remarks
    'When performing calculation, objects like workbooks, worksheets, ranges are
    'usually very slow. To speed up, an array is introduced to hold the data
    'and to calculate from there which is dozens of times faster.

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  'Assign the range of data to an array.
  TheArray = oWs.Range(Cells(cloFirstRow, ciFirstCol), Cells(loRow, iSecondCol))

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  'Status
    'All data is now in TheArray ready for calculation.

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

'  str1 = "Initial Contents in TheArray"
'  For loArr = LBound(TheArray, 1) To UBound(TheArray, 1)
'    For iArr = LBound(TheArray, 2) To UBound(TheArray, 2)
'      If iArr > 1 Then
'        str1 = str1 & Chr(9) 'Next Column
'       Else 'First run-though.
'        str1 = str1 & vbCrLf 'Next Row
'      End If
'      If Not IsError(TheArray(loArr, iArr)) Then
'        str1 = str1 & TheArray(loArr, iArr)
'       Else
'        str1 = str1 & VbaErrorString(TheArray(loArr, iArr))
'      End If
'    Next
'  Next
'  Debug.Print str1
'  str1 = ""

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  'Remarks
    'A one-based array is needed to be pasted into the worksheet via range.

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  'Create a new array for the resulting column.
  ReDim SmallArray(LBound(TheArray) To UBound(TheArray), 1 To 1)

  'Calculate values of the resulting column.
  For loArr = LBound(TheArray, 1) To UBound(TheArray, 1)
    'Read values from TheArray and calculate.
    If IsError(TheArray(loArr, 1)) Then 'First column error
      'VBA Error Handling, the result if both columns contain an error.
      varArr = VbaErrorString(TheArray(loArr, 1))
     Else
      If IsError(TheArray(loArr, 2)) Then 'Second column error
        'VBA Error Handling
        varArr = VbaErrorString(TheArray(loArr, 2))
       Else
        If TheArray(loArr, 1) = "" Or TheArray(loArr, 2) = "" Then '""
           varArr = "#N/A"
         Else
          Select Case TheArray(loArr, 1) 'Equal
            Case TheArray(loArr, 2)
              varArr = True
            Case Is <> TheArray(loArr, 2) 'Not equal
              varArr = False
            Case Else
              varArr = "UNKNOWN ERROR" 'Should never happen.
          End Select
        End If
      End If
    End If
    'Write the results to SmallArray.
    SmallArray(loArr, 1) = varArr
  Next

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  'Status
    'The resulting column containing the results has been written to SmallArray.

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

'  str1 = "Resulting Contents in SmallArray"
'  For loArr = LBound(SmallArray, 1) To UBound(SmallArray, 1)
'    If Not IsError(SmallArray(loArr, 1)) Then
'      str1 = str1 & vbCrLf & SmallArray(loArr, 1)
'     Else
'      'VBA Error Handling
'      str1 = str1 & vbCrLf & VbaErrorString(SmallArray(loArr, 1))
'    End If
'  Next
'  Debug.Print str1

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  'Calculate the range where to paste the data,
  Set oRng = oWs.Range(Cells(cloFirstRow, iSecondCol + 1), _
    Cells(loRow, iSecondCol + 1))
  'Paste the resulting column to worksheet.
  oRng = SmallArray

'  str1 = "Results of the Range"
'  For loArr = 1 To oRng.Rows.Count
'    If Not IsError(oRng.Cells(loArr, 1)) Then
'      str2 = oRng.Cells(loArr, 1)
'     Else
'      'VBA Error Handling
'      str2 = VbaErrorCell(oRng.Cells(loArr, 1))
'    End If
'    str1 = str1 & vbCrLf & str2
'  Next
'  Debug.Print str1

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  'Status
    'The resulting data has been pasted from SmallArray to the resulting
    'column in the worksheet.

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

End Sub
'-------------------------------------------------------------------------------
Function VbaErrorCell(rCell As Range) As String
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'Description
  'Converts a VBA error (variant) IN A RANGE to an Excel error value (string).
'Arguments
  'rCell
    'A cell range with a possible VBA error.
      'If cell range contains more than one cell, the first cell is used.
'Returns
  'An Excel error value (string) if the cell contains an error value, "" if not.

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  Const cVErrLeft As String = "Error 20" 'Debug VBA Error Variable
  Const cStrNewError As String = "New Error. Update this Function!"
  Const cStrNoError As String = ""

''''''''''''''''''''''''''''''''''''''''
  Dim strCStr As String 'The rCell Value Converted to a String
  Dim strRes As String 'One of the Excel Cell Error Values

''''''''''''''''''''''''''''''''''''''''
  strCStr = Left(CStr(rCell(1, 1)), Len(cVErrLeft))
  If strCStr = cVErrLeft Then
    Select Case Right(CStr(rCell), 2)
      Case "00": strRes = "#NULL!"
      Case "07": strRes = "#DIV/0!"
      Case "15": strRes = "#VALUE!"
      Case "23": strRes = "#REF!"
      Case "29": strRes = "#NAME?"
      Case "36": strRes = "#NUM!"
      Case "42": strRes = "#N/A"
      Case Else: strRes = cStrNewError 'New Error.
    End Select
   Else
     strRes = cStrNoError 'Not a VBA Error
  End If
  VbaErrorCell = strRes

''''''''''''''''''''''''''''''''''''''''
End Function
'-------------------------------------------------------------------------------
Function VbaErrorString(strString As Variant) As String
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'Description
  'Converts a VBA error (variant) IN A STRING to an Excel error value (string).
'Arguments
  'strString
    'A string with a possible VBA Error.
'Returns
  'An Excel error value (string) if the cell contains an error value, "" if not.

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
  Const cVErrLeft As String = "Error 20" 'Debug VBA Error Variable
  Const cStrNewError As String = "New Error. Update this Function!"
  Const cStrNoError As String = ""

''''''''''''''''''''''''''''''''''''''''
  Dim strCStr As String 'The strString Value Converted to a String
  Dim strRes As String 'One of the Excel Cell Error Values

''''''''''''''''''''''''''''''''''''''''
  strCStr = Left(CStr(strString), Len(cVErrLeft))
  If strCStr = cVErrLeft Then
    Select Case Right(CStr(strString), 2)
      Case "00": strRes = "#NULL!"
      Case "07": strRes = "#DIV/0!"
      Case "15": strRes = "#VALUE!"
      Case "23": strRes = "#REF!"
      Case "29": strRes = "#NAME?"
      Case "36": strRes = "#NUM!"
      Case "42": strRes = "#N/A"
      Case Else: strRes = cStrNewError 'New Error.
    End Select
   Else
     strRes = cStrNoError 'Not a VBA Error
  End If
  VbaErrorString = strRes

''''''''''''''''''''''''''''''''''''''''
End Function
'-------------------------------------------------------------------------------

Кроме того, с точки зрения автоматизации для автоматического обновления ячеек, вы можете поместить следующий код в окно кода листов:

Option Explicit
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
  XthColumnResult
End Sub

Идеальное решение должно быть сИзмените событие, но оно выдает «Ошибка времени выполнения 28: Недостаточно места в стеке», поэтому вместо этого я использовал событие SelectionChange.
Единственный недостаток, который я смог найти, заключался в том, что при удалении ячейки со значением «del» значениев третьем столбце не обновляется, прежде чем выйти из ячейки.
Как всегда, извините за «закомментирование».

0 голосов
/ 03 октября 2018

Если нет причины, по которой вам нужно сделать это в VBA (поскольку вы не включили в свой код никакого кода), все, что вам нужно, это простая формула рабочего листа.

Если в столбцах A и B содержатся данные, которые необходимо сравнить, начиная со строки 3 (как следует из вашего примера), введите эту формулу в ячейку C3:

=IF(A3&B3="","",A3=B3)

... затем скопируйте / вставьте (из "fill down") формулу по мере необходимости.

Если объединенные значения столбцов A и B равны blank , возвращается пустая строка ("") в противном случае он возвращает сравнение столбцов A и B (TRUE или FALSE).


Кстати, если бы не требование «ничего не возвращать, если пусто», тогда формулабыло так просто, как они получают:

=A3=B3

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...