Call einer Stored Procedure aus PostgreSQL über VBA

JayCole

Aktiver Benutzer
Beiträge
35
Guten Morgen zusammen,

ich würde mich sehr über ein zwei Tipps für folgendes freuen:

Zunächst habe ich (zum ersten Mal in PostgreSQL) eine Stored Procedure (SP) erstellt. Zum Testen auch ein ganz simples Beispiel:

CREATE OR REPLACE PROCEDURE public.gp_lesen(
strnr character varying)
LANGUAGE 'sql'
AS $BODY$
SELECT gpartner FROM projektliste
WHERE nr = strnr;
$BODY$;

Nun versuche ich diese SP über VBA anzusprechen:

Public p_pgCnn As New ADODB.Connection

Sub cnn()
p_pgCnn.Open "Driver={PostgreSQL Unicode};Server=999.999.999.999;Port=9999;Database=meinedatenbank;Uid=meinuser;Pwd=meinkennwort;"
End Sub

Sub StoredProcedureBeispiel01()
pgRcs As New ADODB.Recordset
pgCmd As New ADODB.Command
With pgCmd
.ActiveConnection = p_pgCnn 'die Connection steht permanent global über eine Public Variable
.CommandText = "public.gp_lesen"
.CommandType = adCmdStoredProc
.Parameters("strnr").Value = "123"
Set pgRcs = .Execute 'hier kommt der Fehler public.gp_lesen(unknown) ist eine Prozedur; Error while executing the query
Debug.Print pgRcs.Fields("gpartner").Value
End With
Set pgRcs = Nothing
Set pgCmd = Nothing
End Sub

So funktioniert es in einem MS SQL Server, hatte gehofft, dass ich das auf Postgres so übertragen kann. Was muss ich ändern? Warum beschwert sich der Fehler über eine Prozedur? Natürlich ist es eine Prozedur.

Vielen Dank für Eure Zeit!

P.S. Vielleicht sei kurz erwähnt, dass die PG-Datenbank schon länger läuft und ich auf verschiedenste Weise über VBA und den o.g. CnnString mit SELECT, INSERT, UPDATE ... erfolgreich und sehr zufriedenstellend darauf zugreife. Wegen einem neuen Projekt und großer zu erwartender Datenmenge möchte ich aber nun den Datentransfer über VPN reduzieren und mit SP direkt auf der Datenbank die Datenmenge eben beschränken.
 
Werbung:
Stored Procedures sind nicht dafür gedacht Ergebnisse zurück zu liefern.

Dafür sind Funktionen da.

Code:
CREATE OR REPLACE function public.gp_lesen(strnr character varying)
  returns table (gpartner text)
LANGUAGE sql
AS
$BODY$
  SELECT gpartner
  FROM projektliste
  WHERE nr = strnr;
$BODY$;

Und dann führst Du in Deinem Program einfach ein

Code:
select *
from public.gp_lesen('123456');
aus

und mit SP direkt auf der Datenbank die Datenmenge eben beschränken.

Damit reduzierst Du nicht wirklich die Datenmengen. Die Funktion erzeugt unter Strich den gleichen Datenverkehr wie das äquivalente SELECT (ohne Funktion)
 
Du willst ja was lesen, und das soll ja sicherlich zurück kommen, oder?

Jetzt mal ohne VBA (das kann ich nicht), rein psql:

Code:
edb=*# select * from foo;
 id | data
----+------
  1 |    1
  2 |     
(2 rows)

edb=*# create or replace function foo_lesen(_id int) returns int language sql as $$ select data from foo where id = _id;$$;
CREATE FUNCTION
edb=*# select * from foo_lesen(1);
 foo_lesen
-----------
         1
(1 row)

edb=*#
 
Hallo Castorp,

besten Dank für die schnelle Rückmeldung.

Nicht dafür gedacht, aber funktionieren tut es - zumindest unter MS SQL Server.

Aber ok, mit Funktionen hatte ich mich zum Glück auch schon, wenn auch wenig, beschäftigt.
Eine Function kriege ich samt der Select-Abfrage auf der Postgres-Ebene hin, damit im Grunde auch in VBA mit Recordset.Open und der von Dir genannten Select-Anweisung.
Aber wie hole ich mir das Ergebnis? Ich habe es mit pgRcs.Fields("gpartner").Value probiert, da heißt es "Ein Objekt, das dem angeforderten Namen oder dem ordinalverweis entspricht, kann nicht gefunden werden."
 
Nicht dafür gedacht, aber funktionieren tut es - zumindest unter MS SQL Server.

Ja, aber Postgres ist eben nicht SQL Server - und der steht mit diesem Verhalten auch ziemlich "alleine" da. Eine Migration findet auch im Kopf statt ;)
Migrate your mindset too - Thoughts about SQL

Ich habe es mit pgRcs.Fields("gpartner").
Hmm, ich kenne VBA nicht, aber so wie die Funktion definiert ist, gibt es definitiv eine Spalte "gpartner" in dem Resultat.
 
Ok Castorp, dann mache ich da mal ´n Haken dran. Hätte tatsächlich erwartet oder zumindest gedacht, dass die Datenbanken sich eher in Details, nicht aber in solch generellen Themen unterscheiden.
Das mit der Spalte werde ich dann schon noch irgendwie herausfinden.
Dankeschön!
 
Wenn die "nr" eindeutig ist in der Tabelle, dann kannst Du auch eine Funktion nehmen die keine Tabelle liefert, sondern nur einen Wert:

Code:
CREATE OR REPLACE function gp_lesen(strnr character varying)
  returns text
LANGUAGE sql
AS
$BODY$
  SELECT gpartner
  FROM projektliste
  WHERE nr = strnr;
$BODY$;

Die wird dann mit

Code:
select gp_lesen('12345');

aufgerufen. Vielleicht hat VBA damit weniger Probleme.

Postgres 14 | db<>fiddle
 
Werbung:
Der Vollständigkeit halber, vielleicht hilft es jemandem in Zukunft noch:
In VBA muss ich das Recordset mit einem Feldnamen ansprechen, der der Funktion gleicht, also
Debug.Print Rcs.Fields("meinefunktion").Value
Hab ich gerade mehr oder weniger durch Zufall herausgefunden.
 
Zurück
Oben