Member 12173487 Ответов: 2

Странный вопрос о самостоятельном определении функции в VBA


Приведенный ниже код VBA предназначен для запроса данных из источника данных EXCEL, как и SQL
PUBLIC dic As Object

Function P_query(spath, sFields, swhere, Optional wsName = "Sheet1")
'If Application.Calculation = xlCalculationAutomatic Then Application.Calculation = xlCalculationManual

  Dim rs As New ADODB.Recordset
  Dim sql$, itype$, val
  Dim arrResult
  Dim iscal As Boolean
  If iscal Then Exit Function Else iscal = True
  
  If dic Is Nothing Then Set dic = CreateObject("Scripting.Dictionary")
  P_query = Array("")
  If Len(sFields) = 0 Or sFields = "[]" Then Exit Function
  If Dir(spath, 16) = Empty Then MsgBox "数据源路径不存在": Exit Function
  If Len(swhere) > 0 Then swhere = " where " & swhere

  If Not dic.exists(spath) Then
    Dim cnn As ADODB.Connection
    Set cnn = New ADODB.Connection
    With cnn
      If Application.Version = "11.0" Then
        .Provider = "microsoft.jet.oledb.4.0"
        .ConnectionString = "extended properties=""excel 8.0;HDR=YES;IMEX=1"";data source=" & spath
      Else
        .Provider = "microsoft.ACE.oledb.12.0"
        .ConnectionString = "extended properties=""excel 12.0;HDR=YES;IMEX=1"";data source=" & spath
      End If
      .Open
    End With
    dic.Add spath, cnn
  End If
  
    sql = "select " & sFields & " from [" & wsName & "$]" & swhere
    rs.CursorLocation = adUseClient
    On Error GoTo err1
    rs.Open sql, dic(spath), 1, 1
    If rs.RecordCount = 0 Then P_query = "#N/A": rs.Close: Set rs = Nothing: Exit Function
    If rs.EOF Then rs.MoveFirst
    If rs.Fields(0).Type = 5 Then itype = "Double" Else itype = "String"
    val = rs.GetRows()
    P_query = IIf(IsNull(val(0, 0)), "#N/A", Format(val(0, 0), "standard"))
    rs.Close
    Set rs = Nothing
  Exit Function
err1:
    rs.Close
    Set rs = Nothing
    Set cnn = Nothing
    Set dic = Nothing
    Debug.Print "ERR" & "--" & Err.Description
    P_query = "#Value"
End Function


Что я уже пробовал:

Я вызвал функцию в ячейках excel,странно!!!Некоторые из них работали,в то время как другие терпели неудачу.
И я также отладил его, странно!!!, он циркулировал так, что не мог выскочить из функции, что было еще хуже, публичная переменная dic также не могла работать хорошо,хотя переменная-dic содержала ключ-spath, код "Not dic. exists(spath)" оказался ложным
Итак, я попросил мастера о помощи здесь, ТКС больше нет

Maciej Los

Я бы предложил открыть Recodset в статическом режиме. Следуйте инструкциям, чтобы узнать, почему: Перекодировка.Открытый способ
Еще один совет: используйте SELECT TOP(1) FROM ... чтобы получить единственную запись, а затем value = rs.Fiels(0).

Member 12173487

ТКС больше нет,я исправляю код как " РС.Откройте sql, dic (spath), 3, 1", но он не может работать.

2 Ответов

Рейтинг:
2

CHill60

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

Отладка хороша - это тоже не странно. "Не удалось выпрыгнуть из функции" - затем выясните, куда она ушла (используйте F8, чтобы пройти через нее). Обратите внимание,какие ценности заставляют его висеть. Убедитесь, что у вас есть MoveNext во всех путях через любые циклы.

Следующая строка кода, вероятно, неверна

If Not dic.exists(spath) Then
Почему я думаю, что это неправильно ... потому что затем вы пытаетесь подключиться к файлу в spath только что определив, что файл делает нет существовать.

dic.exists(spath) вернет True, если файл существует. Итак, поставив Not перед ним будет возвращено значение False, если файл существует.


Member 12173487

На самом деле код "dic.exists(spath)" не предназначен для определения того, существует ли файл.Это метка о том, было ли установлено соединение

CHill60

Этот пункт все еще применим. sPath находится в коллекции, поэтому, поставив перед ним not, он вернет False.

Рейтинг:
2

Patrice T

Не решение вашего вопроса, а еще одна проблема, которая у вас есть.
Никогда не создавайте SQL-запрос путем объединения строк. Рано или поздно вы сделаете это с помощью пользовательских вводов, и это откроет дверь уязвимости под названием "SQL injection", она опасна для вашей базы данных и подвержена ошибкам.
Одна кавычка в имени - и ваша программа рухнет. Если пользователь вводит имя типа "Брайан О'Коннер", это может привести к сбою вашего приложения, это уязвимость SQL-инъекции, и сбой-это наименьшая из проблем, вредоносный пользовательский ввод, и он продвигается к командам SQL со всеми учетными данными.
SQL-инъекция-Википедия[^]
SQL-инъекция[^]


Member 12173487

Я думаю, вы правы, это опасно из-за "SQL-инъекции"...Но на самом деле код предназначен только для внутреннего использования и тех, кто владеет источником данных

CHill60

Внутренний или нет, вы должны привыкнуть писать безопасные запросы