Странное форматирование Excel - PullRequest
1 голос
/ 18 мая 2010

Недавно в нашей компании был нанят новый кооператив, которому было поручено подготовить отчет. Отчет запрашивает базу данных и возвращает набор результатов, после чего приступает к созданию электронных таблиц. В зависимости от количества выбранных дней генерируется различное количество отчетов, но я не думаю, что это имеет отношение к вопросу. По сути, он запускает отчеты и просматривает набор результатов, но в какой-то момент продолжает циклически проходить до тех пор, пока не будет остановлено значение 65536, на котором он останавливается. Например, если результирующий набор содержит 74 записи, то первые 74 строки будут отображаться нормально (отформатированы желтым цветом), а все, что после этого будет также отформатировано желтым цветом, хотя его следует оставить в покое. Я наследую этот код, так как я новый кооператив. По-видимому, это происходит только тогда, когда происходит «смена стражи» (новый кооператив должен запустить отчет) .`

DoCmd.SetWarnings False
DoCmd.OpenQuery ("DailySummaryQueryMain")
strSQL = "SELECT * FROM DailySummaryMain"
Set rs = CurrentDb.OpenRecordset(strSQL)
DoCmd.Echo True, "Running first Report"
If Not rs.EOF Then
    rs.MoveFirst

Do While Not rs.EOF And Not rs.BOF
    xlapp.Range("A" & i).Value = rs.Fields(0).Value    
    xlapp.Range("B" & i).Value = rs.Fields(1).Value    
    xlapp.Range("C" & i).Value = rs.Fields(2).Value     


    Set rs2 = CurrentDb.OpenRecordset("SELECT dbo_StatusType.StatusTypeID, dbo_StatusType.Name FROM dbo_StatusType WHERE (((dbo_StatusType.StatusTypeID)=" & rs.Fields(3) & "))")
    rs2.MoveFirst

    xlapp.Range("D" & i).Value = rs2.Fields(1).Value    
    xlapp.Range("E" & i).Value = rs.Fields(4).Value     
    xlapp.Range("F" & i).Value = rs.Fields(5).Value     
    xlapp.Range("G" & i).Value = rs.Fields(6).Value     

    'count number of outages that start and end on same day
    If Format(xlapp.Range("F" & i).Value, "mm/dd/yyyy") = Format(xlapp.Range("G" & i).Value, "mm/dd/yyyy") Then
        dayCount = dayCount + 1
    End If

    xlapp.Range("H" & i).Value = rs.Fields(7).Value    
    xlapp.Range("I" & i).Value = rs.Fields(8).Value     
    xlapp.Range("J" & i).Value = rs.Fields(9).Value     
    xlapp.Range("K" & i).Value = rs.Fields(10).Value    
    xlapp.Range("L" & i).Value = rs.Fields(11).Value    
    xlapp.Range("M" & i).Value = rs.Fields(12).Value    
    xlapp.Range("N" & i).Value = rs.Fields(13).Value    



    'highlite recently modified rows
    If rs.Fields(14).Value = "Yes" Then
        xlapp.Range("A" & i & ":N" & i).Select
        With xlapp.Selection.Interior
            .ColorIndex = 36
            .Pattern = xlSolid
        End With
    End If

    'break apart by sector
    If CInt(rs.Fields(2).Value) = 1 Then
        row = row1
    ElseIf CInt(rs.Fields(2).Value) = 2 Then
        row = row2
    ElseIf CInt(rs.Fields(2).Value) = 3 Then
        row = row3
    Else
        row = row4
    End If




    xlapp.Worksheets(CInt(rs.Fields(2).Value) + 1).Activate
    xlapp.Range("A" & row).Value = rs.Fields(0).Value     
    xlapp.Range("B" & row).Value = rs.Fields(1).Value     
    xlapp.Range("C" & row).Value = rs.Fields(13).Value   
    xlapp.Range("D" & row).Value = rs.Fields(4).Value    
    xlapp.Range("E" & row).Value = rs.Fields(5).Value     
    xlapp.Range("F" & row).Value = rs.Fields(6).Value     
    xlapp.Range("G" & row).Value = rs.Fields(7).Value     
    xlapp.Range("H" & row).Value = rs.Fields(8).Value     
    xlapp.Range("I" & row).Value = rs.Fields(9).Value     
    xlapp.Range("J" & row).Value = rs.Fields(10).Value    
    xlapp.Range("K" & row).Value = ""                     
    xlapp.Range("L" & row).Value = rs.Fields(11).Value    
    xlapp.Range("M" & row).Value = rs.Fields(13).Value   

    If CInt(rs.Fields(2).Value) = 1 Then
        row1 = row1 + 1
    ElseIf CInt(rs.Fields(2).Value) = 2 Then
        row2 = row2 + 1
    ElseIf CInt(rs.Fields(2).Value) = 3 Then
        row3 = row3 + 1
    Else
        row4 = row4 + 1
    End If

    'activate main summary sheet for next outage
    xlapp.Worksheets(1).Activate
    i = i + 1
    rs.MoveNext
Loop`

Также следует отметить, что все это происходит в базе данных доступа, таблицы которой связаны с SQL. Запрос выполняется очень медленно, и я считаю, что это использование представлений, но это ни здесь, ни там. Все, что вам нужно знать - попытка отладки занимает огромное количество времени из-за необходимости ждать возвращения набора записей. Я предполагаю, что не проверять, правильно ли набор результатов пуст. Есть ли способ, которым я мог бы проверить, есть ли значение rs.Fields (0) и основать его на этом, может быть? Это столбец идентификатора, и всегда должно быть значение. Мне интересно, почему rs.EOF не ловит это все же.

Ответы [ 2 ]

2 голосов
/ 19 мая 2010

Несколько замечаний, ни одно из которых не является ответом на ваш вопрос, но может указать вам правильное направление:

Измените свои тесты для пустого набора записей / когда прекратить цикл.

Заменить этот код:

  If Not rs.EOF Then
     rs.MoveFirst
     Do While Not rs.EOF And Not rs.BOF 
       [...]
       rs.MoveNext

... с этим:

  If rs.RecordCount<> 0
     rs.MoveFirst
     Do While Not rs.EOF
       [...]
       rs.MoveNext

Изменить способ использования второго набора записей.

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

  Set rs = CurrentDb.OpenRecordset("SELECT * FROM DailySummaryMain")
  Set rs2 = CurrentDb.OpenRecordset("SELECT dbo_StatusType.StatusTypeID, dbo_StatusType.Name FROM dbo_StatusType ORDER BY dbo_StatusType.StatusTypeID")
  [...]
  rs2.FindFirst "[StatusTypeID]=" & rs.Fields(3)

... Или сделать второй набор записей устаревшим.

Лучше, но, похоже, здесь есть одно совпадение значений, поскольку rs2 никогда не перемещается после первого совпадения, так почему бы не посмотреть, можно ли изменить сохраненный QueryDef "DailySummaryMain", чтобы присоединиться к dbo_StatusType, чтобы значение было прямо в одном наборе записей? Тогда вам вообще не понадобится rs2.

Обычно довольно неразумно ссылаться на поля по порядковому номеру.

Слишком легко полностью объединить вашу подпрограмму, добавив новое поле в исходную инструкцию SELECT в любом месте, кроме конца инструкции SELECT. Итак, измените порядковые номера на фактические имена полей, чтобы rs (0) стал rs («NameOfFirstField»).

Используйте SELECT CASE вместо цепочки If / Then / ElseIf / Else.

Изменить этот код:

  If CInt(rs.Fields(2).Value) = 1 Then
     row = row1
  ElseIf CInt(rs.Fields(2).Value) = 2 Then
     row = row2
  ElseIf CInt(rs.Fields(2).Value) = 3 Then
     row = row3
  Else
     row = row4
  End If

... на это:

  Select Case rs.Fields(2)
    Case 1
      row = row1
    Case 2
      row = row2
    Case 3
      row = row3
    Case 4
      row = row4
  End Select

Или, поскольку все значения, кроме одного, могут быть построены из значения, выполните следующее:

  If rs.Fields(2) = 4 Then
     row = row4
  Else
     row = Eval("row" & rs.Fields(2))
  End If

Контекст не совсем понятен (смысл элементов row и rowN неясен - являются ли они переменными какого-то рода?), Так что, возможно, последний не сработает (Eval () не всегда работать в том случае, если кажется, что так и должно), поэтому я бы, вероятно, пошел с SELECT CASE.

Excel может понадобиться. Значение, но Access нет.

Изменить это:

  xlapp.Range("A" & i).Value = rs.Fields(0).Value

... на это:

  xlapp.Range("A" & i).Value = rs.Fields(0)

Вам может и не понадобиться эта часть уравнения в Excel.

2 голосов
/ 18 мая 2010

65536 имеет значение, так как его значение на 1 больше максимального значения, которое может быть сохранено в 16-битном целом числе без знака ... поэтому что-то где-то переполняется.

Это не будет целое число VBA, поскольку они подписаны, но я все равно заменил бы CInt() s на CLng() и гарантировал бы, что переменные счетчика, такие как i, будут объявлены как long

Запускали ли вы его с отключенной обработкой ошибок, чтобы увидеть, возникают ли какие-либо ошибки?

Что касается отладки, вы можете перейти к ADO, запустить его один раз и сохранить результаты на диск (RS.Save), а затем RS.Open этот файл для последующих запусков.

...