Excel VBA: vlookup для поиска строки даты в таблице диапазона дат - PullRequest
1 голос
/ 23 октября 2019

Привет и заранее спасибо за любую помощь. Извлечение ежедневных файлов с датой в ячейке. Мне нужно использовать дату, чтобы найти, к какой неделе она относится, в таблице с датами начала и окончания в двух столбцах. В последующих столбцах есть больше данных, которые мне нужно извлечь, как только я узнаю строку, в которую попадает дата. Таблица перекрестных ссылок имеет следующий формат: переменную даты (назначенную как строковым, так и переменным даты), выбранную из источника, необходимо сравнить с столбцами A и B, чтобы выяснить, в какую строку она поместится, и затем извлечь финансовый год. (Col A), а также краткое описание (Col F)

Таблица перекрестных ссылок
enter image description here

Скорректировано и переименованоконечный файл выглядит так

enter image description here

Ответы [ 3 ]

1 голос
/ 24 октября 2019

Функциональность, описанную здесь, может быть реализована с помощью формул ячеек без использования функции VBA. Я включил 2 возможных решения.

Я немного упростил сценарий. Предположим, что таблица перекрестных ссылок (расположена в Sheet1 файла XR.xlsx) содержит только эти 3 столбца:

          A               B               C
   +--------------+---------------+---------------+
 1 | PDWK_St_Date | PDWK_End_Date | Short_Descrip |
   +--------------+---------------+---------------+
 2 | 07-Nov-16    | 13-Nov-16     | P1W1          |
 3 | 14-Nov-16    | 20-Nov-16     | P1W2          |
 4 | 21-Nov-16    | 27-Nov-16     | P1W3          |
 5 | 28-Nov-16    | 04-Dec-16     | P1W4          |
 6 | 05-Dec-16    | 11-Dec-16     | P2W1          |
 7 | 12-Dec-16    | 18-Dec-16     | P2W2          |
 8 | 19-Dec-16    | 25-Dec-16     | P2W3          |
 9 | 26-Dec-16    | 01-Jan-17     | P2W4          |
10 | 02-Jan-17    | 08-Jan-17     | P3W1          |
11 | 09-Jan-17    | 15-Jan-17     | P3W2          |
12 | 16-Jan-17    | 22-Jan-17     | P3W3          |
13 | 23-Jan-17    | 29-Jan-17     | P3W4          |
14 | 30-Jan-17    | 05-Feb-17     | P4W1          |
15 | 06-Feb-17    | 12-Feb-17     | P4W2          |
16 | 13-Feb-17    | 19-Feb-17     | P4W3          |
17 | 20-Feb-17    | 26-Feb-17     | P4W4          |
18 | 27-Feb-17    | 05-Mar-17     | P5W1          |
   +--------------+---------------+---------------+

Решение 1 (упрощенное)

Itработает только в том случае, если диапазоны дат являются последовательными (т. е. дата начала = дата окончания предыдущей строки + 1 день) - его случай в таблице перекрестных ссылок.

В рабочей книге назначения используйте VLOOKUP для обращения ктаблица перекрестных ссылок:

=VLOOKUP(B2,[XR.xlsx]Sheet1!$A$2:$C$18,3,TRUE)

Вышеприведенная формула относится к строке 2 в таблице назначения и предполагает, что «бизнес-дата» находится в столбце B (следовательно, B2 в 1-м параметре), 2-й параметр -диапазон поиска, 3 в 3-м параметре означает, что извлекаемое значение находится в 3-м столбце, а TRUE позволяет сопоставлять даты в пределах диапазона (от даты начала до даты начала следующей строки).

Обратите внимание, что формула можетлегко копировать в другие строки, например, перетаскивая маркер заполнения (маленький квадрат в правом нижнем углу ячейки).

Решение 2

В этомpproach, бизнес-дата сравнивается с начальной и конечной датами из таблицы перекрестных ссылок. Вместо VLOOKUP используются функции INDEX и MATCH:

=INDEX([XR.xlsx]Sheet1!$C$2:$C$18,MATCH(1,(B2>=[XR.xlsx]Sheet1!$A$2:$A$18)*(B2<=[XR.xlsx]Sheet1!$B$2:$B$18),0),1)

Здесь рабочая дата (ячейка B2) сравнивается как с начальной, так и с конечной датой, результаты умножаются(эквивалентно логическому И) и соответствует 1 (т. е. ИСТИНА).

ВАЖНО: после вставки этой формулы (например, в строку формулы для ячейки C2) вам нужно нажать Ctrl+Shift+Enter вместо обычного Enter. Это указывает на так называемую «формулу массива» (она же формула CSE);в противном случае наши сравнения внутри MATCH не будут работать так, как задумано. Вы можете обратиться к этому сообщению для получения дополнительной информации. Формулы CSE показывают в скобках в скобках. Хорошей новостью является то, что они могут быть воспроизведены так же, как и все другие формулы.

Таблица назначения будет выглядеть примерно так:

      A           B              C       
   +------+---------------+-------------+
 1 | Unit | Business Date | Short Descr |
   +------+---------------+-------------+
 2 | 1102 | 26-Aug-17     | #N/A        |
 3 | 1102 | 05-Jan-17     | P3W1        |
 4 | 1102 | 06-Feb-17     | P4W2        |
 5 | 1102 | 11-Nov-16     | P1W1        |
 6 | 1102 | 02-Feb-17     | P4W1        |
 7 | 1102 | 01-Oct-16     | #N/A        |
   +------+---------------+-------------+

Обратите внимание, что в случае решения 1 ячейка C2будет содержать P5W1 вместо # N / A - это потому, что для сравнения не использовалась конечная дата.

1 голос
/ 27 октября 2019

Функция, предоставляемая @PGTester, прекрасно работала, когда в коде было решено несколько вопросов:

1) Объявления. Все объявления были в одной строке для каждого типа. Это не работает в VBA, поскольку только последняя переменная объявлена ​​как предназначенная, а все предыдущие объявлены как вариант. (т. е. DIM adate, bdate, cdate в качестве даты) В этом примере только cdate является фактической датой. Передача adate функции приводила к несоответствию, пока объявления не были исправлены. (На это указал @Domenic)

2) Форматы дат: хотя все даты в исходном файле и файле перекрестных ссылок до форматирования были отформатированы как «гггг-ммм-дд», ошибка 13Несоответствие типов по-прежнему препятствовало продвижению кода вперед. Изменение формата на «md-yyyy» как в исходном файле (выполнено в коде), так и в таблице перекрестных ссылок (вручную перед доступом) решило проблему, и следующий код работал, как и ожидалось.

3) Указание вызовов функций в файле перекрестных ссылок как для vlookup, так и для rnglookup было выполнено путем создания и установки переменных для необходимых страниц. Это упростило выбор при необходимости.

Set variables for next steps
'
    Set CRef = Workbooks.Open(refFILE)
    Set shtJOB = CRef.Sheets("JobCross")
    Set shtDATE = CRef.Sheets("fcalendar")
    sht.Activate
    Set rngJOBS = Range("i2:i" & lastRow)
    Set rngJBGRP = shtJOB.Range("A1:b16")
    Set rng = shtDATE.Range("A2:f210")

Выполнен код с обеими функциями:

Sub CleanDaily_Labour()
'
' CleanDaily_Labour Macro
' RMDC Payroll Resarch (MU) Report prep
'

' Note the separate declarations for each variable
'    
    Dim myPath As String, fName As String, refFILE As String, job As String, _
      JobGR As String, DateST As String, WKDay As String, PDWK As String
    Dim CRef As Workbook, wkb As Workbook
    Dim shtDATE As Worksheet, shtJOB As Worksheet, sht As Worksheet
    Dim aDate As Date, fYR As Date
    Dim fYear As Variant
    Dim rng As Range, rngJOBS As Range, rngJBGRP As Range
    Dim SC As Long, lastRow As Long, PD As Long, WK As Long

    ' Application.ScreenUpdating = False
    myPath = Application.ActiveWorkbook.Path
'
' Get the file date and assign to variables
'
    Range("D3").Select
    **Selection.NumberFormat = "m-d-yyyy"**
    aDate = Range("D3").Value
    DateST = WorksheetFunction.Text(aDate, "YYYYMMDD")
    WKDay = WorksheetFunction.Text(aDate, "DDD")

    Selection.Copy
    Range("D7").Select
    ActiveSheet.Paste
'
' Rename and save the active workbook by date
' set wkb to new workbook name and assign calendar cross ref
'
    fName = myPath & "\Daily_Labour_" _
        & DateST & ".xlsx"
    ActiveWorkbook.SaveAs fName, 51
    Set wkb = Workbooks.Open(fName)
    Set sht = wkb.Sheets("Sheet1")


    refFILE = myPath & "\Cross_Ref_fCalendar.xlsx"

'
' Remove extra header info
'
    Rows("1:5").Select
    Application.CutCopyMode = False
    Selection.Delete Shift:=xlUp
'
'   Insert Column to the left of Column D
'
    Columns("E:G").Insert Shift:=xlToRight, _
      CopyOrigin:=xlFormatFromRightOrBelow
'
' Update Headers that will be kept / used
'
    Range("A1").Value = "FYear"
    Range("E1").Value = "PD_WK"
    Range("J1").Value = "JOB_GRP"
    Range("F1").Value = "WKDay"
    Range("G1").Value = "PD"
    Range("H1").Value = "WK"
'
    Rows("1:1").Select
    With Selection
        .HorizontalAlignment = xlCenter
    End With
'
' Remove extra columns
'
    Sheets("Sheet1").Range("K:K,M:P,R:AY").EntireColumn.Delete
'
' Get the last row and fill known columns
'
    lastRow = Cells(Rows.Count, 1).End(xlUp).row
    Range("d2:d" & lastRow).Value = aDate
    Range("d2:d" & lastRow).NumberFormat = "m-d-yyyy"
    Range("f2:f" & lastRow).Value = WKDay
'
' Set variables for next steps
'
    Set CRef = Workbooks.Open(refFILE)
    Set shtJOB = CRef.Sheets("JobCross")
    Set shtDATE = CRef.Sheets("fcalendar")
    sht.Activate
    Set rngJOBS = Range("i2:i" & lastRow)
    Set rngJBGRP = shtJOB.Range("A1:b16")
    Set rng = shtDATE.Range("A2:f210")
'
' Loop through jobs in column i match job in shtJOB
' put matching group in row j (Use Function vLookupVBA)
'
    For Each jRow In rngJOBS
        jRow.Select
        job = ActiveCell.Value
        JobGR = VLookupVBA(job, rngJBGRP, Null)
        ActiveCell.Offset(0, 1).Value = JobGR
    'end for
   Next jRow
'
'Save Progress during testing:
'
   Application.DisplayAlerts = False
   ActiveWorkbook.SaveAs fName, 51
'
' Fill in date parameters from Cross Ref file for Business date
' Use function rngLOOKUP to update variables then set ranges to the variables
' May be more efficient to get row number from cross ref table instead - later.
'
    shtDATE.Activate '(does not seem to affect)
'
    fYear = rngLOOKUP(aDate, rng, 3)
    PDWK = rngLOOKUP(aDate, rng, 6)
    PD = rngLOOKUP(aDate, rng, 4)
    WK = rngLOOKUP(aDate, rng, 5)
'
' Fill the columns with the variables (can likely bypass the variables and put on 1 line)- later
'
    sht.Activate
    Range("A2:A" & lastRow).Value = fYear
    Range("E2:E" & lastRow).Value = PDWK
    Range("G2:G" & lastRow).Value = PD
    Range("H2:H" & lastRow).Value = WK
'
' Close reference file
'
    Application.DisplayAlerts = False
    CRef.Close False
'
' Cleanup, save and close workbooks
'
    Application.DisplayAlerts = False
    wkb.SaveAs fName, 51
'
' SQL call: Load to existing datbase (GDrive), use same format as Transactions
' ?? Get sales by day? vs maintain PDWK - Future
'
    Application.DisplayAlerts = True
    Application.ScreenUpdating = True
'    wkb.Close.false



End Sub
Private Function VLookupVBA(what As Variant, lookupRng As Range, defaultValue As Variant) As Variant
    Dim rv As Variant: rv = Application.VLookup(what, lookupRng, lookupRng.Columns.Count, False)
    If IsError(rv) Then
        VLookupVBA = "NULL"
    Else
        VLookupVBA = rv
    End If
End Function

Public Sub UsageExample()
    MsgBox VLookupVBA("ValueToFind", ThisWorkbook.Sheets("ReferenceSheet").Range("A:D"), "Not found!")
End Sub
Function rngLOOKUP(chkDate As Date, rngf As Range, theColumn As Long) As Variant
Dim acell As Range

'
For Each acell In rngf.Columns(1).Cells
    If acell.Value <= chkDate And acell.Offset(0, 1).Value >= chkDate Then
        rngLOOKUP = acell.Offset(0, theColumn - 1).Value
        Exit Function
    End If
Next acell

rngLOOKUP = "#Nothing"

End Function
0 голосов
/ 23 октября 2019

Эта пользовательская функция похожа на Vlookup, где она сравнивает первые два столбца диапазона как дату, а если входная дата попадает в диапазон, она возвращает соответствующий столбец.

Function rngLOOKUP(aDate As Date, rng As Range, theColumn As Long) As Variant
Dim acell As Range

For Each acell In rng.Columns(1).Cells
    If acell.Value <= aDate And acell.Offset(0, 1).Value >= aDate Then
        rngLOOKUP = acell.Offset(0, theColumn - 1).Value
        Exit Function
    End If
Next acell

rngLOOKUP = "#Nothing"

End Function

В этом файле Excel вы можете увидеть его в действии. Или смотрите скриншот ниже. Ячейка выделения имеет пользовательскую формулу.

enter image description here

...