Страница 1 из 3
Удаление строки по условию
Добавлено: 09 апр 2009, 14:35
kuznetsovSergey
Подскажите как задать условие. при котором будет удаляться строка? Код для макроса. на VB для Excel.
К примеру на листе список есть 3 столбца. Если значение первого столбца не совпало со значением третьего столбца, то он удаляет такую строчку
--------------------------------------------------------------------------------
Добавленное сообщение
--------------------------------------------------------------------------------
я вижу это примерно так:
Код: Выделить всё
Sub Macros()
Dim Spisok As Worksheet
Set Spisok = ThisWorkbook.Sheets("page")
While Spisok.Cells(r, 1) <> ""
If (Left(Sheets("page").Cells(r, 15).Value, Len(b)) = b) Or (Sheets("page").Cells(r, 15).Value = d) _
Or ((Sheets("page").Cells(r, 12).Value <> e) And _
(Sheets("page").Cells(r, 12).Value <> f) And (Sheets("page").Cells(r, 12).Value <> g)) Then
Spisok.Rows(r).Delete
End If
Wend
r = r + 1
End Sub
--------------------------------------------------------------------------------
Добавленное сообщение
--------------------------------------------------------------------------------
либо так :
Код: Выделить всё
Sub Macros()
While Sheets("page").Cells(r, 1) <> ""
If (Left(Sheets("page").Cells(r, 15).Value, Len(b)) = b) Or (Sheets("page").Cells(r, 15).Value = d) _
Or ((Sheets("page").Cells(r, 12).Value <> e) And _
(Sheets("page").Cells(r, 12).Value <> f) And (Sheets("page").Cells(r, 12).Value <> g)) Then
Rows("r:r").Select
Selection.Delete Shift:=xlUp
End If
r = r + 1
Wend
End Sub
--------------------------------------------------------------------------------
Добавленное сообщение
--------------------------------------------------------------------------------
Но дело в том. что не один вариант не работает. не понимаю что делать ...
--------------------------------------------------------------------------------
Добавленное сообщение
--------------------------------------------------------------------------------
ну понятное дело. что за переменные, я здесь принимаю какие то собственные значения. И с ними сравниваю значение ячеек.
Re: Удаление строки по условию
Добавлено: 09 апр 2009, 15:01
Aent
Hint: Проходите список снизу-вверх
Re: Удаление строки по условию
Добавлено: 09 апр 2009, 15:05
kuznetsovSergey
да разницы не вижу, он ошибку номер 400 пишет, не понимаю в чем дело ..
--------------------------------------------------------------------------------
Добавленное сообщение
--------------------------------------------------------------------------------
какая разница идти снизу списка? делая дополнительный цикл, у меня производительность на первом месте, мне важна скорость работы, нежели чем я буду прогонять цикл по подсчету кол-ва строк, и идти сконца. Когда я могу Идти сверху. и при удалении строки. пониматься на строчку выше, чтобы продолжить дальнейшую проверку условия. У меня в табличке не 10 записей, а бывает и по 30000-65000 строк, не ужели мне прогонять целый цикл по ним ... в Холостую
Re: Удаление строки по условию
Добавлено: 09 апр 2009, 23:04
Teslenko_EA
Здравствуйте
kuznetsovSergey.
Табличные данные хранимые в том числе на листах Excel, удобнее обрабатывать с применением ADO. Для этого необходимо:
" писал(а):макрос для Excel! от soulthiefer
1 подключите к проекту файла, в котором будет выполняться код библиотеку ADO (меню Tools \ References… -Microsoft ActiveX Data Objects X.X ...).
2. первая строка таблицы должна содержать имена полей используемых в запросе, например: w1, w2, w3, w4, w5...
3. в модуле проекта поместите подобный код:
Код: Выделить всё
Sub updateExcel()
Dim cn As New ADODB.Connection, rs As ADODB.Recordset, sVar$
'строка подключения к источнику данных - текущий, сохраненный(!) файл Excel
sVar = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + ThisWorkbook.Path + "\" + _
ThisWorkbook.Name + ";Extended Properties=""Excel 8.0;HDR=Yes"";"
'--------------------------------------------
'Текст запроса подразумевает, что данные расположены на листе "Лист1"
'в ячейках A1, B1, C1 записаны имена полей "W1", "W2", "W3" соответственно:
Const SQL_SEL$ = "SELECT d.W1, d.W2, d.W3 FROM [Лист1$A1:C65000] as d WHERE (d.W1=d.W3);"
' [Лист1$A1:C65000] - имя листа и используемый диапазон
'--------------------------------------------
'
Set cn = New Connection
cn.Open sVar
'
Set rs = New ADODB.Recordset
rs.Open SQL_SEL, cn, adOpenKeyset, adLockReadOnly
'данные из Recordset'а будут помещены на "Лист2"
Sheets("Лист2").Range("A2").CopyFromRecordset rs
rs.Close: Set rs = Nothing
cn.Close: Set cn = Nothing
End Sub
результат будет помещен на другой лист, и в этом выигрыш по скорости, обработка 65000 строк займет пару секунд, для Вас это важно:
" писал(а):У меня в табличке не 10 записей, а бывает и по 30000-65000 строк, не ужели мне прогонять целый цикл по ним ... в Холостую
Евгений.
Re: Удаление строки по условию
Добавлено: 10 апр 2009, 00:05
Aent
Вот общая схема удаления строки текущего листа, удовлетворяющей некоему условию. Предполагается что самый длинный столбец - первый
Код: Выделить всё
Dim n as long
Dim i as long
Application.ScreenUpdating = False
n = cells(cells.rows.count,1).end(xlUP).row 'номер последней строки
for i = n to 1 step - 1
if Строку_Надо_Удалить then rows(i).delete
next i
Application.ScreenUpdating = True
Re: Удаление строки по условию
Добавлено: 10 апр 2009, 10:13
kuznetsovSergey
Teslenko_EA писал(а):Здравствуйте kuznetsovSergey.
результат будет помещен на другой лист, и в этом выигрыш по скорости, обработка 65000 строк займет пару секунд, для Вас это важно:Евгений.
Дело в том, что этот цикл будет участвовать во многих циклах. И Работа макроса и так уже работает довольно затяжно. И по паре секунд выгодать из каждого секунда, подарит порядка 2-3 минут выйгрыша. Это довольно приятно
--------------------------------------------------------------------------------
Добавленное сообщение
--------------------------------------------------------------------------------
Народ это уже становится не смешным ...
вот даже такой код не работает:
Код: Выделить всё
Sub Macros()
Dim n As Long
Dim i As Long
b = "111"
d = "222"
e = "333"
f = "444"
g = "555"
Application.ScreenUpdating = False
n = Cells(Cells.Rows.Count, 1).End(xlUp).Row
For i = n To 1 Step -1
If (Left(Sheets("name_page").Cells(r, 15).Value, Len(b)) = b) Or (Sheets("name_page").Cells(r, 15).Value = d) _
Or ((Sheets("name_page").Cells(r, 12).Value <> e) And _
(Sheets("name_page").Cells(r, 12).Value <> f) And (Sheets("name_page").Cells(r, 12).Value <> g)) Then
Rows(i).Delete
End If
Next i
Application.ScreenUpdating = True
End Sub
--------------------------------------------------------------------------------
Добавленное сообщение
--------------------------------------------------------------------------------
Teslenko_EA писал(а):Здравствуйте
kuznetsovSergey.
Табличные данные хранимые в том числе на листах Excel, удобнее обрабатывать с применением ADO. Для этого необходимо:
Код: Выделить всё
Sub updateExcel()
Dim cn As New ADODB.Connection, rs As ADODB.Recordset, sVar$
'строка подключения к источнику данных - текущий, сохраненный(!) файл Excel
sVar = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + ThisWorkbook.Path + "\" + _
ThisWorkbook.Name + ";Extended Properties=""Excel 8.0;HDR=Yes"";"
'--------------------------------------------
'Текст запроса подразумевает, что данные расположены на листе "Лист1"
'в ячейках A1, B1, C1 записаны имена полей "W1", "W2", "W3" соответственно:
Const SQL_SEL$ = "SELECT d.W1, d.W2, d.W3 FROM [Лист1$A1:C65000] as d WHERE (d.W1=d.W3);"
' [Лист1$A1:C65000] - имя листа и используемый диапазон
'--------------------------------------------
'
Set cn = New Connection
cn.Open sVar
'
Set rs = New ADODB.Recordset
rs.Open SQL_SEL, cn, adOpenKeyset, adLockReadOnly
'данные из Recordset'а будут помещены на "Лист2"
Sheets("Лист2").Range("A2").CopyFromRecordset rs
rs.Close: Set rs = Nothing
cn.Close: Set cn = Nothing
End Sub
результат будет помещен на другой лист, и в этом выигрыш по скорости, обработка 65000 строк займет пару секунд, для Вас это важно:Евгений.
этот код пообще безграмотный. Где оптимизация, не для конкретно заачи, а и другие варианты. Данный код медленный, и не универсальный... что за диапозон 65000 ???? зачем образабывать все строки, а если у меня будет всего 1000 строк, зачем я буду лишних 64000 строк проверять??? Производительность на первом месте. Количество заполненных строк надо сначала считать, а уж потом с ними работать. Тем более код данной задачи, не предлагает критерий отбора, если не соответствует то удаляет строку. Я вообще не вижу текст кодда который должен удалять строку ..
Re: Удаление строки по условию
Добавлено: 10 апр 2009, 14:41
Aent
kuznetsovSergey, Ну раз уж зашла речь о безграмотности...
1) В приведённом вами коде в качестве номера строки используется
r в то время как цикл по
i... Некоторые граммотные люди используют
Option Explicit для недопущения подобных ошибок

2) Классификатор
Sheets("name_page"). неэффективно прописывать у каждой
cells. Его необходимо вынести в конструкцию
Код: Выделить всё
With Worksheets("name_page")
.Cells(....)
End with
3)
len(b) нужно вычислять ВНЕ цикла. Это сэконмит несколько микросекунд.
4) Поскольку VBA сам толком не умеет оптимизировать код целесообразно
в начале тела цикла присваивать .cells(i,12) и .cells(i,15) cтроковым переменным
и работать с ними.
5) Более эффективно вместо кучи OR использовать конструкцию
Select-Case
Код: Выделить всё
....
s15 = .cells(i,15).value
Select Case .Cells(i, 12).Value
Case e,f,g
if s15 =d then
.Rows(i).delete
elseif left$(s15,len_b) = b then
.Rows(i).delete
end if
Case Else
.Rows(i).delete
End Select
Re: Удаление строки по условию
Добавлено: 10 апр 2009, 14:49
kuznetsovSergey
Aent писал(а):kuznetsovSergey, Ну раз уж зашла речь о безграмотности...
1) В приведённом вами коде в качестве номера строки используется
r в то время как цикл по
i... Некоторые граммотные люди используют
Option Explicit для недопущения подобных ошибок

2) Классификатор
Sheets("name_page"). неэффективно прописывать у каждой
cells. Его необходимо вынести в конструкцию
Код: Выделить всё
With Worksheets("name_page")
.Cells(....)
End with
3)
len(b) нужно вычислять ВНЕ цикла. Это сэконмит несколько микросекунд.
4) Поскольку VBA сам толком не умеет оптимизировать код целесообразно
в начале тела цикла присваивать .cells(i,12) и .cells(i,15) cтроковым переменным
и работать с ними.
5) Более эффективно вместо кучи OR использовать конструкцию
Select-Case
Код: Выделить всё
s15 = .cells(i,15).value
Select Case .Cells(i, 12).Value
Case e,f,g
if s15 =d then
.Rows(i).delete
elseif left$(s15,len_b) = b then
.Rows(i).delete
end if
Case Else
.Rows(i).delete
End Select
[code][/quote]
какая разница как назвать цикл? )))))))
i цикл у меня используется уже в макросе
а то что я прошу, это будет встроенный цикл.
А вот по поводу case в принципе признаю свою ошибку, хотя or не так много, но case я учту, спасибо.
Re: Удаление строки по условию
Добавлено: 10 апр 2009, 14:58
Aent
Как назвать переменную цикла разницы конечно нет. Но она должна быть одна и та же в FOR и в теле цикла ...
Re: Удаление строки по условию
Добавлено: 10 апр 2009, 15:06
kuznetsovSergey
Aent писал(а):Как назвать переменную цикла разницы конечно нет. Но она должна быть одна и та же в FOR и в теле цикла ...
мне что сюда весь макрос выкладывать что ли? )))
я грамотно сформулировал поставленную задачу, и потом вставлю нормальное решение этой задачи в код. А какая названа переменная в цикле, я думаю для грамотных людей это не так важно, буть она хоть словом.