简体   繁体   English

如何在保存到 OneDrive 的 Excel 工作簿中运行 SQL 查询?

[英]How can I run a SQL query within an Excel Workbook saved to OneDrive?

I would like to run SQL queries on tables all contained within a single Excel workbook.我想对包含在单个 Excel 工作簿中的表运行 SQL 查询。 My VBA code uses ADODB to run these SQL queries.我的 VBA 代码使用 ADODB 运行这些 SQL 查询。

Opening connection fails when the workbook is saved in OneDrive, but works when workbook is saved to a local drive.将工作簿保存在 OneDrive 中时打开连接失败,但将工作簿保存到本地驱动器时可以正常工作。

How can I run SQL on tables within a single excel workbook, while saved on OneDrive?如何在单个 excel 工作簿中的表上运行 SQL,同时保存在 OneDrive 上?

The code works when the book is saved locally but not on OneDrive.当书籍保存在本地但不在 OneDrive 上时,该代码有效。 The only change is the file path which looks fairly different in each case:唯一的变化是在每种情况下看起来完全不同的文件路径:

OneDrivePathExample = "https://d.docs.live.net/....xlsb"

LocalPathExample = "C:\My Documents\....xlsb"

I've experimented with a few things around the file path in the connection string but, unsurprisingly, they didn't work:我已经在连接字符串中的文件路径周围尝试了一些东西,但不出所料,它们没有工作:

  1. Original原来的

    Provider=Microsoft.ACE.OLEDB.12.0;Data Source=https://d.docs.live.net/.../Documents/Financial Tracker.xlsb;Extended Properties="Excel 12.0;HDR=Yes;IMEX=1";
  2. Replacing "/" with "\"将“/”替换为“\”

     Provider=Microsoft.ACE.OLEDB.12.0;Data Source=https:\\d.docs.live.net\...\Documents\Financial Tracker.xlsb;Extended Properties="Excel 12.0;HDR=Yes;IMEX=1";`
  3. Adding square brackets around path在路径周围添加方括号

    Provider=Microsoft.ACE.OLEDB.12.0;Data Source=[https://d.docs.live.net/.../Documents/Financial Tracker.xlsb];Extended Properties="Excel 12.0;HDR=Yes;IMEX=1";
  4. Adding quotes around path在路径周围添加引号

    Provider=Microsoft.ACE.OLEDB.12.0;Data Source="https://d.docs.live.net/.../Documents/Financial Tracker.xlsb";Extended Properties="Excel 12.0;HDR=Yes;IMEX=1";

I realize that I can avoid this by saving it locally when running this code, and then save it back to OneDrive afterwards but I would like to avoid this if possible.我意识到我可以通过在运行此代码时将其保存在本地来避免这种情况,然后再将其保存回 OneDrive,但如果可能的话,我想避免这种情况。

I also realize that I can write VBA code that does what I'm trying to do with SQL, however I did that originally but switched to the SQL method because SQL was way faster. I also realize that I can write VBA code that does what I'm trying to do with SQL, however I did that originally but switched to the SQL method because SQL was way faster.

Here's my code:这是我的代码:

Function OpenRST(strSQL As String) As ADODB.Recordset
''Returns an open recordset object

Dim cn As ADODB.Connection
Dim strProvider As String, strExtendedProperties As String
Dim strFile As String, strCon As String

strFile = ThisWorkbook.FullName

strProvider = "Microsoft.ACE.OLEDB.12.0"
strExtendedProperties = """Excel 12.0;HDR=Yes;IMEX=1"";"


strCon = "Provider=" & strProvider & _
     ";Data Source=" & strFile & _
     ";Extended Properties=" & strExtendedProperties

Set cn = CreateObject("ADODB.Connection")
Set OpenRST = CreateObject("ADODB.Recordset")

cn.Open strCon  ''This is where it fails

OpenRST.Open strSQL, cn

End Function

On the cn.Open strCon line, the following error appears:cn.Open strCon行,出现如下错误:

Run-time error '-2147467259 (80004005)';运行时错误'-2147467259(80004005)';
Method 'Open' of object '_Connection' failed object '_Connection' 的方法 'Open' 失败

Thanks!谢谢!

this is my solution to get file path.这是我获取文件路径的解决方案。

'This Function search root folder as C: ,D: ...
'Search into all OneDrive folders
Option Explicit
Private Const strProtocol   As String = "Http"
Private Const pathSeparator As String = "\"

Function MainFindFile(ByRef NullFilePath As String, Optional FileName As String) As Boolean
    
    Dim fso                 As FileSystemObject 'Necessary enable microsoft scripting runtime in references
    Dim UserRootFolder      As Folder
    Dim SecondSubFolders    As Folder
    Dim ThirdSubFolders     As Folder
    Dim InitialPath         As String
    Dim OneDriveFolderName  As String
    
    Set fso = New Scripting.FileSystemObject
    
    InitialPath = ActiveWorkbook.FullName
    If FileName = vbNullString Then FileName = ActiveWorkbook.Name

    If InStr(1, InitialPath, strProtocol, vbTextCompare) > 0 Then
        InitialPath = Environ("SystemDrive")
        InitialPath = InitialPath & Environ("HomePath")
        
        'Gets all folders in user root folder
        Set UserRootFolder = fso.GetFolder(InitialPath)
        
        For Each SecondSubFolders In UserRootFolder.SubFolders
            'Searches all folders of OneDrive, you may have how many Onedrive's folders as you want
            If InStr(1, SecondSubFolders.Name, "OneDrive", vbTextCompare) > 0 Then
                OneDriveFolderName = InitialPath & pathSeparator & SecondSubFolders.Name
                'Verifies if file exists in root of Onedrive Folder
                MainFindFile = SearchFile(OneDriveFolderName, FileName, NullFilePath)
                If MainFindFile Then Exit For

                'Uses recursive function to percur all subfolders in root of OneDrive
                For Each ThirdSubFolders In fso.GetFolder(OneDriveFolderName).SubFolders
                    MainFindFile = RecursiveFindFile(ThirdSubFolders, FileName, NullFilePath)
                    If MainFindFile Then Exit For
                Next ThirdSubFolders
            End If
            If MainFindFile Then Exit For
        Next SecondSubFolders
        
    End If
    
    MsgBox NullFilePath
    
End Function
Private Function RecursiveFindFile(Folder As Folder, FileName As String, ByRef NullFilePath As String) As Boolean

    Dim fso         As FileSystemObject
    Dim objFolder   As Folder
    Dim Result      As Boolean
    
    Set fso = New Scripting.FileSystemObject
    
    'Verifies if file exists in root of Onedrive Folder
    RecursiveFindFile = SearchFile(Folder.Path, FileName, NullFilePath)
    If RecursiveFindFile Then Exit Function
    
    For Each objFolder In Folder.SubFolders
        If Not SearchFile(objFolder.Path, FileName, NullFilePath) Then
            RecursiveFindFile = RecursiveFindFile(objFolder, FileName, NullFilePath)
            If RecursiveFindFile Then Exit For
        Else
            RecursiveFindFile = True
            Exit For
        End If
    Next objFolder
    
End Function
Private Function SearchFile(Path As String, FileName As String, ByRef NullFilePath As String) As Boolean
    
    'NullFilePath is a byref variable to be filled by this function
    Dim fso As New Scripting.FileSystemObject
    
    If fso.FileExists(Path & pathSeparator & FileName) Then
        NullFilePath = Path & pathSeparator & FileName
        SearchFile = True
    End If
    
End Function

You can use the following function to convert the OneDrivePath into a LocalPath .您可以使用以下函数将OneDrivePath转换为LocalPath

There are many solutions for this problem out there on the web, but almost none that work for all the different kinds of OneDrive accounts and folders... ( personal , business , business with SharePoint , synchronized folders from other people's OneDrives , etc.)对于这个问题,网上有很多解决方案,但几乎没有一个适用于所有不同类型的 OneDrive 帐户和文件夹......(个人商业SharePoint业务、来自其他人的 OneDrives 的同步文件夹等)

That's why I wrote this function which deals with all kinds of OneDrive mounts I have encountered so far.这就是为什么我编写了这个函数来处理我迄今为止遇到的各种 OneDrive 挂载。

Private Function GetLocalPath(path As String) As String
    Const HKEY_CURRENT_USER = &H80000001
    Dim objReg As Object
    Dim regPath As String
    Dim subKeys() As Variant
    Dim subKey As Variant
    Dim strValue As String
    Dim strMountpoint As String
    Dim strSecPart As String
    
    Static pathSep As String
    If pathSep = "" Then pathSep = Application.PathSeparator
    
    Set objReg = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\default:StdRegProv")
    regPath = "Software\SyncEngines\Providers\OneDrive\"
    objReg.EnumKey HKEY_CURRENT_USER, regPath, subKeys

    For Each subKey In subKeys
        objReg.GetStringValue HKEY_CURRENT_USER, regPath & subKey, _
                            "UrlNamespace", strValue
        If InStr(path, strValue) > 0 Then
            objReg.GetStringValue HKEY_CURRENT_USER, regPath & subKey, _
                                "MountPoint", strMountpoint
            strSecPart = Replace(Mid(path, Len(strValue)), "/", pathSep)
            GetLocalPath = strMountpoint & strSecPart
            
            Do Until Dir(GetLocalPath, vbDirectory) <> "" Or _
                     InStr(2, strSecPart, pathSep) = 0
                strSecPart = Mid(strSecPart, InStr(2, strSecPart, pathSep))
                GetLocalPath = strMountpoint & strSecPart
            Loop
            Exit Function
        End If
    Next
    GetLocalPath = path
End Function

Note that you could in theory just use "\" instead of Application.PathSeparator because this problem only occurs on Windows and therefore this function is only necessary on Windows systems.请注意,理论上您可以只使用"\"而不是Application.PathSeparator ,因为此问题仅发生在 Windows 上,因此此功能仅在 Windows 系统上是必需的。

Replace the htpps: with "".将 html: 替换为“”。 This will bring you one step further.这会让你更进一步。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM