Как Excel "понимает", какой в пределах какого диапазона сортировать?

Мне нужно сортировать таблицу по четырём столбцам. Часто. Поэтому пишу макрос. Тот, что написал я (не буду приводить тут его код, потому что: 1. вопрос его не касается; 2. не хочу "раздувать" вопрос), не работает до конца. По этой причине я записал макрос макро рекордером, найдя в группе "Редактирование" Инструмент "Сортировка и фильтр" и кликнув "Настраиваемая сортировка". Добавил три уровня к существующему одному и выбрал нужные мне столбцы. Вот что получилось на выходе:

Sub macro_record()
    ActiveWorkbook.Worksheets("Sheet1").AutoFilter.Sort. _
        SortFields.Clear
    ActiveWorkbook.Worksheets("Sheet1").AutoFilter.Sort. _
        SortFields.Add Key:=Range("A2:A1000000"), SortOn:=xlSortOnValues, Order:= _
        xlAscending, DataOption:=xlSortNormal
    ActiveWorkbook.Worksheets("Sheet1").AutoFilter.Sort. _
        SortFields.Add Key:=Range("C2:C1000000"), SortOn:=xlSortOnValues, Order:= _
        xlAscending, DataOption:=xlSortNormal
    ActiveWorkbook.Worksheets("Sheet1").AutoFilter.Sort. _
        SortFields.Add Key:=Range("E2:E1000000"), SortOn:=xlSortOnValues, Order:= _
        xlAscending, DataOption:=xlSortTextAsNumbers
    ActiveWorkbook.Worksheets("Sheet1").AutoFilter.Sort. _
        SortFields.Add Key:=Range("G2:G1000000"), SortOn:=xlSortOnValues, Order:= _
        xlAscending, DataOption:=xlSortNormal
    
    With ActiveWorkbook.Worksheets("Sheet1").AutoFilter. _
        Sort
        .Header = xlYes
        .MatchCase = False
        .Orientation = xlTopToBottom
        .SortMethod = xlPinYin
        .Apply
    End With
End Sub

Вопрос в следующем: как Excel "понимает", какой именно диапазон нужно сортировать? Иными словами, в какой строке кода программа передаёт компьютеру адрес диапазона для сортировки?


Ответы (1 шт):

Автор решения: vikttur_Stop_RU_war_in_UA

Об автофильтре (закладка Данные-Фильтр)

Диапазон, который попадает под действие автофильтра, зависит от расположения данных и диапазона, выделенного перед установкой фильтра.

введите сюда описание изображения

введите сюда описание изображения

Самое простое (вар.1): выделен весь диапазон с данными - в фильтре все выделенные, включая строки, которые расположены ниже пустой строки (разрыв данных).

Выделен не весь диапазон с данными. В фильтр попадают данные всех столбцов выделенного диапазона (вар.2), а вот со строками начинается... Нужно понимать, что автофильтр сам старается определить заголовки и диапазон для фильтрации.

Выделена одна ячейка в диапазоне с данными (вар.3) - в фильтре весь диапазон ячеек с данными, ограниченный пустыми столбцами и строками (т.е. если ниже пустой строки есть данные, они в фильтр не попадают). То же, если выделен диапазон, который включает все столбцы с данными и первая строка которого - это первая строка с данными (вар.4).

Выделена одна ячейка, вокруг которой нет данных - в фильтре нет фильтруемых ячеек, только заголовок (вар.5)

Выделен диапазон не с первой строки с данными (вар.6, вар.7)- строки выше в фильтр не попадают.

Если ячейка пустая и есть контакт со строкой выше, в которой есть данные, в фильтр попадет и строка с выделенной ячейкой (вар.8, вар.9)

Если ячейка пустая и нет контакта с ячейками, в которых есть данные, автофильтр не установится (вар.10).

и т.д.

О сортировке (закладка Данные-Сортировка)

Здесь можно задать настраиваемую сортировку: очередность (по столбцам или строкам), порядок (по возрастанию, по убыванию, по списку), вид (по значению, цвету).

Есть несколько нюансов.

Если нужный диапазон не выделен, диапазон фильтрации определяется автоматически (почти как в автофильтре) - относительно активной ячейки.

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

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

Все эти моменты нужно учитывать при записи макроса.

Sub macro_record()
    With Worksheets("Sheet1")
        With .Range("A1:G2000")
            .Parent.AutoFilterMode = False
            .AutoFilter
        End With
        
        With .AutoFilter.Sort
            With .SortFields
                .Clear
                .Add Key:=Range("A2:A2000"), SortOn:=xlSortOnValues, _
                                Order:=xlAscending, DataOption:=xlSortNormal
                .Add Key:=Range("C2:C2000"), SortOn:=xlSortOnValues, _
                                Order:=xlAscending, DataOption:=xlSortNormal
                .Add Key:=Range("E2:E2000"), SortOn:=xlSortOnValues, _
                                Order:=xlAscending, DataOption:=xlSortTextAsNumbers
                .Add Key:=Range("G2:G2000"), SortOn:=xlSortOnValues, _
                                Order:=xlAscending, DataOption:=xlSortNormal
            End With

            .Header = xlYes: .MatchCase = False
            .Apply
        End With
    End With
End Sub 

Указываем диапазон (.Range("A1:G2000")); для исключения ошибки при установке фильтра снимаем фильтр(.AutoFilterMode = False); ставим фильтр (.AutoFilter); задаем параметры сортировки (.SortFields); заголовки - да, есть (.Header = xlYes); регистр учитывать не нужно (.MatchCase = False); просим применить заданную сортировку к нашему объекту (.AutoFilter.Sort.Apply)

Но так ли нужен автофильтр? Сортировать можно без него. Заодно добавим определение высоты диапазона (переменную LastRow)

Sub macro_record()
    Dim LastRow As Long
    
    With Worksheets("Sheet1")
        LastRow = .UsedRange.Rows.Count - .UsedRange.Row + 1
 
        With .Sort
            With .SortFields
                .Clear
                .Add Key:=Range("A2:A" & LastRow), SortOn:=xlSortOnValues, _
                                Order:=xlAscending, DataOption:=xlSortNormal
                .Add Key:=Range("C2:C" & LastRow), SortOn:=xlSortOnValues, _
                                Order:=xlAscending, DataOption:=xlSortNormal
                .Add Key:=Range("E2:E" & LastRow), SortOn:=xlSortOnValues, _
                                Order:=xlAscending, DataOption:=xlSortTextAsNumbers
                .Add Key:=Range("G2:G" & LastRow), SortOn:=xlSortOnValues, _
                                Order:=xlAscending, DataOption:=xlSortNormal
            End With
            
            .SetRange Range("A1:G" & LastRow)
            .Header = xlYes: .MatchCase = False
            .Apply
        End With
    End With
End Sub

Диапазон сортировки задается строкой

Worksheets("Sheet1").Sort.SetRange Range("A1:G" & LastRow)

А так как указано, что заголовки есть (Sort.Header = xlYes), то сортируемые диапазоны указаны со второй строки.

Показанные коды работают на активном листе

→ Ссылка