Прошу помочь, как удалить строки из большой таблицы, которые есть уже в 2 разных таблицах на других листах.
Есть 3 таблицы на 6 тысяч строк и 62 столбца, где столбцы c E по BH скрыты Нужно чтобы из Таблицы_1 удалялись полностью строки, которые есть в Таблице_2 и Таблице_3 Уникальный ключ: Артикул
Нашел макрос, который удаляет строки, которые содержат текст, который вводишь в пользовательское поле.
Но им можно удалять только по одному артикулу, а у меня несколько тысяч строк.
Как модифицировать этот макрос, чтобы условия для удаления можно было задавать в столбце - скажем вставить список артикулов, которые надо удалить в столбце.
Home1 пишет: Нужно чтобы из Таблицы_1 удалялись полностью строки, которые есть в Таблице_2 и Таблице_3
Как вариант, если подобное надо делать постоянно и на больших объемах, обратиться к Access. И в нем все это делать одним запросом - записи без подчиненных, или же по ключевому/мым полю/ям...
А артикулы в Таблица_2 и Таблица_3 не повторяются?
Макрос в модуль листа "Таблица_1"
Option Explicit
Sub Udalenie() Dim artikul As String Dim FoundArtikul As Range Dim iLastRow As Long Dim i As Long iLastRow = Cells(Rows.Count, 1).End(xlUp).Row For i = iLastRow To 2 Step -1 artikul = Cells(i, 1) Set FoundArtikul = Sheets("Таблица_2").Columns(1).Find(artikul, , xlFormulas, xlWhole) If Not FoundArtikul Is Nothing Then Cells(i, 1).EntireRow.Delete End If Set FoundArtikul = Sheets("Таблица_3").Columns(1).Find(artikul, , xlFormulas, xlWhole) If Not FoundArtikul Is Nothing Then Cells(i, 1).EntireRow.Delete End If Next End Sub
Прекрасно понимаю, что самый быстрый способ быть посланным в сад в поиск - это создать тему или даже вопрос на тему "поиск сроки с условием". Поэтому последние 3-4 часа копался сам. Около 20 тем есть только на этом форуме. Тем не менее, то ли лыжи..
В общем, вынужден снова попросить вашей помощи.
Описание задачи: На листе есть несколько сотен тысяч строк. Пустых строк нет. Надо организовать быстрое удаление строк при одновременном выполнении двух условий: 1) в указанной колонке есть слово "Все". 2) поле Дата данной строки (колонка С) не должна быть меньше "даты зачистки" DateFrom. При этом, условие 1) имеет некую особенность - если макрос вызывается для колонки В (артикул товара), то вместо слова "Все" при вызове процедуры используется слово "_CSKU". В этом случае удалению подлежат все строки, в которых число в колонке CSKU >= 1 000 000. При этом второе условие (дата) также должно выполняться.
Таким образом данная часть макроса должна вырезать сводные данные начиная с некой даты. В последующем сводные данные по всем складам будут снова перерассчитаны и перезалиты на данный лист. Хотя наверное, это уже лишняя информация .
К сожалению, подавляющее большинство примеров не учитывает скорость работы макроса, и в результате работает со скоростью 200..5000 строк в минуту. В итоге 600 000 / 5000 - получаем вечность. Но подходящее решение было найдено в виде ссылки на этом форуме http://www.sql.ru/forum/722758/udalenie-strok-v-bolshom-eksel-fayle.
Но к сожалению, даже это, как говорится, разжеванное для особо одаренных, мне не помогло.
Поэтому, буду благодарен тому, кто поможет мне разобраться с вопросом модернизации макроса под мою ситуацию. Кстати, для одного столбца он работает действительно буквально секунды. Более чем устраивает. Теперь дело за малым - упросить макрос не мочить строчки, в которых дата меньше даты урезания.
Прикладываю пример. В нем условно датой урезания принято 01.07.13 Для удобства, во всех строках, где я покопался, я поставил комментарий "!!!" После запуска test_del_row должны удалиться все строки с красными ячейками. Желтые удалятся, когда я запущу макрос для колонок D, и потом - F (я решил не делать это в одном вызове - меня устроит 3 вызова, т.к. макрос будет использоваться в разных частях и универсальность мне важнее). Зеленые строки не будут удалены никогда, т.к. находятся до даты урезания. К сожалению, сейчас макрос этого не понимает и удаляет их.
Скрытый текст
Код
' функция удаления строк по критерию
'===================================================================================
' Sub : DelRows(TableHeader,ColNum,DelValue)
' TableHeader : Range; table header range
' ColNum : Long; column number with DelValue
' DelValue : Variant; value of rows to be deleted
' DateFrom : с какой даты начиная нужно удалять !!! ДОБАВИЛ Я.
'-------------+---------------------------------------------------------------------
' VBA call : DelRows ActiveSheet.Range("A1:H1"), 5, 0
'-------------+---------------------------------------------------------------------
' Created : ZVI:2009:12:26 http://www.sql.ru/forum/actualthread.aspx?tid=722758
'-----------------------------------------------------------------------------------
Sub DelRows(TableHeader As Range, ColNum As Long, DelValue, DateFrom As Date) '!!! добавил DateFrom
Dim Arr(), r&, rs&, cs&, i&, v, ac
With TableHeader.CurrentRegion
rs = .Rows.Count - TableHeader.Row + .Row
cs = .Columns.Count - TableHeader.Column + .Column
End With
With TableHeader.Resize(rs, 1)
Arr() = .Offset(, cs).Value
' Arr_Date() = .Offset(, 2).Value !!! Пытался решить задачу созданием массива-дублера (именно для колонки дат),
' но думаю что лучше как то обойтись одним массивом
' Check DelValue
For Each v In .Offset(, ColNum - 1).Value
r = r + 1
If Not ((v = DelValue) Or (DelValue = "_CSKU" And IsNumeric(v) And v >= 1000000)) Then
' !!! быть хорошей строкой ты можешь только если
' !!! ты не содержишь: а) слова "Все" (передается в DelValue при вызове процедуры)
' !!! либо б) числа больше миллиона и при этом DelValue = "_CSKU"
' !!! Именно в этот IF надо как-то вставить проверку даты из колонки В
' !!! OR ((Дата из В) < DateFrom) - тогда ты всегда хорошая строка,
' !!! и чего бы в тебе не было, тебя мы удалять не будем
i = i + 1 ' !!! уже при размещении файла на форуме, обратил внимание, что не понимаю откуда i взялась то...
Arr(r, 1) = 1
End If
Next
If i < rs Then
' Freeze on
With Application
.ScreenUpdating = False
.EnableEvents = False
ac = .Calculation: .Calculation = xlCalculationManual
End With
' Delete rows with DelValue in ColNum
.Offset(, cs) = Arr
.Resize(, cs + 1).Sort .Cells(1).Offset(, cs), 1, Header:=xlNo
.Resize(, 1).Offset(, cs).ClearContents
.Resize(rs - i, cs).Offset(i).Clear ' или .Resize(rs - i).Offset(i).EntireRow.Delete
' Freeze off
With Application
.ScreenUpdating = True
.EnableEvents = True
.Calculation = ac
End With
End If
End With
End Sub
Sub Test_del_rows()
DelRows ActiveSheet.Range("A1:G1"), 2, "_CSKU", #7/1/2013#
End Sub
Этот макрос написан для анализа одного столбца. Если нужно анализировать сразу несколько столбцов - тогда почти половину кода нужно переписывать. Цикл For Each нужно менять на for x= n to m, чтоб привязаться к другому массиву. Сейчас реализовывать некогда...
Этот макрос написан для анализа одного столбца. Если нужно анализировать сразу несколько столбцов - тогда почти половину кода нужно переписывать. Цикл For Each нужно менять на for x= n to m, чтоб привязаться к другому массиву. Сейчас реализовывать некогда...
Да я что-то такое подозревал. Сейчас тоже голова уже не варит. Попробую посмотреть еще раз модицикации макроса автором на другие темы, по-моему там было несколько колонок. Но самая шальная мысль была изначально - тупо создать для столбца дат массив-зеркало, который бы подглядывал на индекс основного массива, подсказывал ему что там с датой по этой же строке и при этом полностью бы дублировал все действия с индексами/размерами основного массива. Вся проблема опять-таки в законе подлости - именно массивы я не изучил детально и кое-какие моменты перевода мысли автора даются с трудом. Как говорится, будем искать Вот нюхом чувствую, что буквально парой фраз тут где-то должно быть счастье - уж очень не хочется менять макрос на другой - там ведь тоже могут быть свои грабли. Жаль что в копилке идей так и не появилось "самого правильного макроса для удаления строки по нескольким критериям" Огромное спасибо за поддержку!
"Надо просто делать так: сначала в каком-нибудь одном столбце сформируйте с помощью формул некоторые значения, а затем уже примените DelRows к этому столбцу, указав значение, по которому нужно удалять."
Применительно к Вашему примеру, нужно сделать так:
1. Запишите, например, в ячейку AA2 такую формулу: =--ЕСЛИ(C2>=ДАТА(2013;7;1); ИЛИ( B2>=1000000; D2="Все"; F2="Все" ) )
В начале формулы для удобства добавлены два минуса, чтобы строки удаления помечать единичкой, а не логическим значением ИСТИНА.
2. Скопируйте или протяните ячейку с формулой вниз до последней строки с данными
3. Используйте любую версию макроса DelRows для удаления строк. При этом в качестве столбца значений укажите AA (27-й столбец), а в качестве DelValue укажите единичку.
4. Удалите вспомогательную формулу из столбца AA. Этот столбец можно и просто скрыть для последующего использования.
Если при этом включить макрорекордер, и немного причесать код, то все 4 пункта могут выполняться и автоматически.
P.S. Вариант макроса (версия 7) для любых сложных критериев отбора уже сделал, после документирования выложу отдельно, здесь приведу ссылку.
Если это всё задумывается для обработки отчётов 1С - то может быть лучше сразу писать код для импорта только нужного из txt? Я не знаю какие там отчёты выгружаете, но может быть удобнее выгружать текст, затем макросом выбирать только нужные строки. Или как вариант - подключать текст как источник внешних данных к ACCESS и там уже запросом выбирать нужное. Или ещё вариант - брать только нужное в EXCEL с помощью MSQuery.
ZVI, спасибо! Видимо, я вчера уже "поплыл" и пропустил этот момент, возможно из-за того, что что-либо писать в ячейки воспринимал как прямой риск сделать процедуру еще дольше. Сейчас понимаю, что если формулу прописать с умом, то получится очень даже ничего - то что и надо. Спасибо!
Hugo, из txt итак берутся данные, которые нужны. Проблема в том, что эти данные могут в течение 1-2 недель корректироваться (задним числом) и мне надо каждый день просто перезаливать последние 2 недели.
Я подозреваю, что рано или поздно я столкнусь или с проблемами со скоростью (вернее это произошло уже сейчас, но они пока решаются, т.к. причина в моих кривых руках) или упрусь в количество строк на листе Excel. Понятно, что сегментированием проблему можно будет отсрочить, но рано или поздно это может стать серьезной преградой - все-таки Excel не база данных. Но здесь хорошие новости в том, что я сам управляю глубиной истории в данных и как только начну упираться в предел емкости или производительности - просто отрежу 1 квартал. А сейчас именно Excel + макросы дают мне беспрецедентное удобство в создании прототипа будущей серьезной системы (она будет на 1С). Это такой новый вид написания технического задания для программистов 1С - вместо "вот наброски на бумаге как это примерно может выглядеть" получаем "вот вам работающий код на VBA - сделайте тоже самое в 1С" .
Спасибо Вам за помощь!
Ребята, вы реально делаете очень благое дело! Сейчас посмотрел во скольких темах в людям помогаете - реально круто! МОЛОДЦЫ!