web-dev-qa-db-fra.com

Exécution de requêtes SQL sur une table Excel dans un classeur avec une macro VBA

J'essaye de faire une macro Excel qui me donnera la fonction suivante dans Excel:

=SQL("SELECT heading_1 FROM Table1 WHERE heading_2='foo'")

Me permettant de rechercher (et peut-être même d'insérer) des données dans les tables de mon classeur à l'aide de requêtes SQL.

C'est ce que j'ai fait jusqu'à présent:

Sub SQL()

Dim cn As ADODB.Connection
Dim rs As ADODB.Recordset

strFile = ThisWorkbook.FullName
strCon = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & strFile _
& ";Extended Properties=""Excel 12.0;HDR=Yes;IMEX=1"";"

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

cn.Open strCon

strSQL = "SELECT * FROM [Sheet1$A1:G3]"

rs.Open strSQL, cn

Debug.Print rs.GetString

End Sub

Mon script fonctionne comme un charme avec des plages codées en dur telles que celle de l'extrait de code ci-dessus. Cela fonctionne également très bien avec les plages nommées statiques.

Cependant, cela ne fonctionnera pas avec les plages nommées dynamiques ni avec TABLE NAMES, qui est le plus important pour moi.

La réponse la plus proche que j'ai trouvée est celle d'un type souffrant de la même maladie: http://www.ozgrid.com/forum/showthread.php?t=72973

Aider quelqu'un?

Modifier

Je l'ai déjà préparé, je peux ensuite utiliser le nom résultant dans mes requêtes SQL. La limite est que je dois savoir sur quelle feuille se trouvent les tableaux. Pouvons-nous faire quelque chose à ce sujet?

Function getAddress()

    myAddress = Replace(Sheets("Sheet1").Range("Table1").address, "$", "")
    myAddress = "[Sheet1$" & myAddress & "]"

    getAddress = myAddress

End Function

Merci!

27

Une des choses que vous pouvez faire est d’obtenir l’adresse de la plage nommée dynamique et de l’utiliser comme entrée dans votre chaîne SQL. Quelque chose comme:

Sheets("shtName").range("namedRangeName").Address

Ce qui crachera une chaîne d'adresse, quelque chose comme $A$1:$A$8

Modifier:

Comme je l'ai dit dans mon commentaire ci-dessous, vous pouvez obtenir dynamiquement l'adresse complète (y compris le nom de la feuille) et l'utiliser directement ou analyser le nom de la feuille pour une utilisation ultérieure:

ActiveWorkbook.Names.Item("namedRangeName").RefersToLocal

Ce qui donne une chaîne comme =Sheet1!$C$1:$C$4. Donc, pour votre exemple de code ci-dessus, votre instruction SQL pourrait être

strRangeAddress = Mid(ActiveWorkbook.Names.Item("namedRangeName").RefersToLocal,2)

strSQL = "SELECT * FROM [strRangeAddress]"
12
Jake Bathman
Public Function GetRange(ByVal sListName As String) As String

Dim oListObject As ListObject
Dim wb As Workbook
Dim ws As Worksheet

Set wb = ThisWorkbook

For Each ws In wb.Sheets
    For Each oListObject In ws.ListObjects
        If oListObject.Name = sListName Then
            GetRange = "[" & ws.Name & "$" & Replace(oListObject.Range.Address, "$", "") & "]"
        Exit Function
        End If
    Next oListObject
Next ws


End Function

Dans votre code SQL, utilisez-le comme ceci

sSQL = "Select * from " & GetRange("NameOfTable") & ""
8
Johan Kreszner

S'appuyant sur la routine de Joan-Diego Rodriguez avec l'approche de Jordi et une partie du code de Jacek Kotowski - Cette fonction convertit tout nom de table du classeur actif en une adresse utilisable pour les requêtes SQL. 

Note à MikeL: L'ajout de "[#All]" inclut les en-têtes permettant d'éviter les problèmes que vous avez signalés.

Function getAddress(byVal sTableName as String) as String 

    With Range(sTableName & "[#All]")
        getAddress= "[" & .Parent.Name & "$" & .Address(False, False) & "]"
    End With

End Function
4
Craig Hatmaker

Je suis un débutant qui bricole le code de quelqu'un d'autre, soyez donc indulgent et corrigez davantage mes erreurs. J'ai essayé votre code et joué avec l'aide de VBA Ce qui suit a fonctionné avec moi:

Function currAddressTest(dataRangeTest As Range) As String

    currAddressTest = ActiveSheet.Name & "$" & dataRangeTest.Address(False, False)

End Function

Lorsque je sélectionne l'argument de source de données pour ma fonction, il est converti au format Sheet1 $ A1: G3. Si Excel le change en référence à Table1 [#All] dans ma formule, la fonction fonctionne toujours correctement 

Je l'ai ensuite utilisé dans votre fonction (essayé de jouer et d'ajouter un autre argument à injecter dans WHERE ...

Function SQL(dataRange As Range, CritA As String)

Dim cn As ADODB.Connection
Dim rs As ADODB.Recordset
Dim currAddress As String



currAddress = ActiveSheet.Name & "$" & dataRange.Address(False, False)

strFile = ThisWorkbook.FullName
strCon = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & strFile _
& ";Extended Properties=""Excel 12.0;HDR=Yes;IMEX=1"";"

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

cn.Open strCon


strSQL = "SELECT * FROM [" & currAddress & "]" & _
         "WHERE [A] =  '" & CritA & "'  " & _
         "ORDER BY 1 ASC"

rs.Open strSQL, cn

SQL = rs.GetString

End Function

En espérant que votre fonction se développe davantage, je la trouve très utile. Bonne journée!

2
Jacek Kotowski

Répondez simplement à la deuxième partie de votre question sur l’obtention du nom de la feuille où se trouve un tableau:

Dim name as String

name = Range("Table1").Worksheet.Name

Modifier:

Pour que les choses soient plus claires: quelqu'un a suggéré d'utiliser Range sur un objet Sheet. Dans ce cas, vous n'avez pas besoin; la plage où vit la table peut être obtenue en utilisant le nom de la table; ce nom est disponible dans tout le livre. Donc, appeler Range seul fonctionne bien.

1
Jordi

Hi a récemment étudié la question et a rencontré des problèmes pour référencer le tableau nommé (objet liste) dans Excel

si vous placez le suffixe '$' sur le nom de la table, tout va bien dans le monde

Sub testSQL()

    Dim cn As ADODB.Connection
    Dim rs As ADODB.Recordset

    ' Declare variables
    strFile = ThisWorkbook.FullName

    ' construct connection string
    strCon = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & strFile _
    & ";Extended Properties=""Excel 12.0;HDR=Yes;IMEX=1"";"

    ' create connection and recordset objects
    Set cn = CreateObject("ADODB.Connection")
    Set rs = CreateObject("ADODB.Recordset")

    ' open connection
    cn.Open strCon

    ' construct SQL query
    strSQL = "SELECT * FROM [TableName$] where [ColumnHeader] = 'wibble';"

    ' execute SQL query
    rs.Open strSQL, cn

    Debug.Print rs.GetString

    ' close connection
    rs.Close
    cn.Close
    Set rs = Nothing
    Set cn = Nothing
End Sub
0
MikeL