Как 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 шт):
Об автофильтре (закладка Данные-Фильтр)
Диапазон, который попадает под действие автофильтра, зависит от расположения данных и диапазона, выделенного перед установкой фильтра.
Самое простое (вар.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), то сортируемые диапазоны указаны со второй строки.
Показанные коды работают на активном листе

