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!
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]"
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") & ""
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
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!
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.
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