SQL über Makros ausführen

Liebe community,

ich habe einen Knoten im Kopf und komme überhaupt nicht weiter, bitte sehr um Eure Unterstützung!

Ich möchte in einem Base-Formular über einen Push Button ein Makro aufrufen (das krieg ich hin), das dann folgendes macht: Die Werte aus Tabelle1 an Tab2 dranhängen, sodass in Tab2 die *IDs erzeugt werden (das werden dann später meine Rechnungsnummern).

Den SQL-Befehl hab ich, direkt ausführen über Tools>SQL funktioniert.

Das Makro liegt direkt in der Datei, in der auch die Tabellen liegen. Ist alles lokal, nicht passwortgeschützt und Makros sind eingeschaltet.

Daher meine Fragen:

  • Was muss ich ins Makro schreiben, um die Tabellen ansteuern zu können (nicht der SQL-Befehl, sondern das “Drumherum”)
  • Muss ich die Tabellen ins Formular einbinden? Wenn ja, an welcher Stelle?
  • Ich hätte gerne eine Lösung, die auf Benennung von Subformularen usw. verzichtet, damit das alles schön flexibel bleibt. Geht das in der Art?

Ich wäre um Hinweise sehr froh, mit Internet-Recherche und der Literatur bin ich auf keinen grünen Zweig gekommen. Wie gesagt, Knoten im Hirn :crazy_face:

Herzliche Grüße!
David

Ich habe so etwas noch nicht gemacht. Aber meine Suche führt mich auf https://wiki.documentfoundation.org/Documentation/BASIC_Guide#Forms. Vielleicht ist das etwas für dich dabei. Wenn du mit den Development Tools arbeitest solltest du das Control-Element unter Shapes finden.

Es ist in deiner Beschreibung nicht klar, ob deine “Tabelle” eine Writertabelle ist oder ob es sich um ein Table-Control des Formulars handelt.

Du kennst den Base-Guide, dessen deutsche Version von RobertG geschrieben wird?
.
Was Dein konkretes Problem angeht: Wenn wir von Tabellen in Base reden kann Dein Macro das erledigen, ohne dass im Formular irgendetwas ausser dem Startknopf steht.
.
Vgl:

Sub RunSQLButton(e)
Const cMsgbox = True
Const cMaxLen = 1000
Const cTitle = "Command "
oModel = e.Source.Model
frm = oModel.getParent()
oCon = frm.ActiveConnection
aTags() = split(oModel.Tag, ";")
n = uBound(aTags)
for i = 0 to n
	s = trim(aTags(i))
	sMsg = s
	if len(s) > cMaxLen then sMsg = Left(s, cMaxLen) & cHR(10) &" [...]"
	if len(s)>0  then
		If cMsgbox then
			x = Msgbox(sMsg, 33, cTitle &  i +1 &"/"& n +1 )
		else
			x = 1
		endif
		if x = 2 then exit sub 'Cancel
		oStmt = oCon.prepareStatement(s)
		on error goto errMsg
			r = oStmt.executeUpdate()
		if cMsgbox then Msgbox r &" records affected", 64, cTitle
	endif
next
frm.reload()
exit sub
errMsg:
error(err)
End Sub

Weise einer Formular-Schaltfläche das Makro zu. Schreibe das SQL-Statement (oder mehrere mit Semicolon getrennt) in das Feld “Zusatzinformation” dieser Schaltfläche. Das SQL wird dann ausgeführt. Willst Du die Meldungen unterdrücken weil Du sicher bist, was Du tust, dann setze Const cMsgbox = False.

1 Like

Vielen herzlichen Dank für die Hinweise!! :smiley:

Mir fehlt jetzt noch der Hinweis, ob Du das so hingekriegt hast und wenn nicht, warum nicht. Elaborierte Hinweise ohne Feedback können auf Dauer ziemlich frustrieren.

Funktionieren tut es noch nicht ganz, ich bin noch dabei zu verstehen wie das mit der Verbindung zur Datenbank läuft, schau mir dazu Eure Hinweise durch und auch noch weitere, die ich gefunden habe. Mit dem Guide bin ich nicht weitergekommen, da hab ich natürlich davor schon reingeschaut gehabt.

Mit Deinem Code bekomm ich zwar keine Fehlermeldungen mehr, aber es passiert auch noch nichts. Wird aber sicherlich werden!

Kopier doch einfach den Code in irgendein Modul und füge eine Schaltfläche (push button) zu Deinem Formular hinzu. Dann noch Deinen erprobten SQL-Code in die “Zusatzinformation” und los geht’s. Ach ja, Schalftlächen-Event “Ausführen” noch dem Makro zuweisen.

oCon = frm.ActiveConnection nimmt die Verbindung, die durch das Formular eh schon besteht.
Sub RunSQLButton(e) jedes Event-Makro gibt ein Event-Sruct an die aufgerufene Routine.
oModel = e.Source.Model e.Source ist das aufrufende Objekt, Das Model davon ist das, was man im Eigenschaften-Dialog des Objekts sieht.
aTags() = split(oModel.Tag, ";")Dort sieht man unter anderm die “Zusatzinformationen” (Tag Eigenschaft)
frm = oModel.getParent() das Elternobjekt eines Schaltflächen-Models ist immer ein Formular (s. Form-Navigator). Bei Elementen in Tabellenkontrollfeldern ist das etwas komplizierter.
oCon = frm.ActiveConnection Da haben wir doch schon eine bestehende Verbindung zur Datenbank,
Stmt = oCon.prepareStatement(s) und diese Verbindung kann ein SQL-Statement kompilieren,
r = oStmt.executeUpdate() das dann ausgeführt werden kann und die Anzahl der betroffenen Zeilen zurück gibt.

Das alles kann man unmöglich auswendig lernen. Man schlägt es nach, indem man zuerst das Anwendungsprogramm zu beherrschen lernt und sich dann durch die Objekthierarchie der UNO API hangelt. Zu letzterem dienen Extensions wie MRI oder XRay.

So, jetzt hab ichs glaub ich so simpel wies möglich ist:

Option Explicit

'------------------------------------------------------------------

Sub MyMacro()

if IsNull(ThisDatabaseDocument.CurrentController.ActiveConnection) then
    ThisDatabaseDocument.CurrentController.connect
endif

Dim oStatement As Object
dim sStr as string

sStr = "INSERT INTO ""t_Rechnungsnummern"" (""ID_Kunde"") select ""ID_Kunde"" from ""v_Leistungen_offen"""

oStatement = ThisDatabaseDocument.CurrentController.ActiveConnection.createStatement()
oStatement.execute(sStr)

End sub
'------------------------------------------------------------------

Hab in der englischen Abteilung was gefunden:
https://ask.libreoffice.org/t/run-sql-in-the-current-base-database/47965
Dieses relevante Detail hat mir gefehlt, jetzt ist vieles klarer.

Danke Dir @Villeroy, mit Deinem Code hab ich auch wieder viel gelernt! Stück für Stück wirds!!

Das ist alles viel zu kompliziert, vor allem wenn man weder MRI noch Xray benutzt.
EDIT
ThisDatabaseDocument bezieht sich auf das Datenbankdokument, wo der Code eingebettet ist. Ist der Code gar nicht in ein Datenbankdokument eingebettet, dann scheitert das schon mal, und man muss ThisComponent verwenden, was sich sowohl auf das aktive Datenbankdokument oder ein aktives Formulardokument beziehen könnte.
Jetzt kann es in diesem Fall natürlich sinnvoll erscheinen, das Makro gar nicht von einem Formular aus aufzurufen, wie von meinem Code vorausgesetzt, sondern von einer Symbolleiste, einem Menü oder aus den Makro-DIalogen heraus. Dann musst Du aber überlegen, woher das Makro den SQL-Code beziehen soll. Kann man natürlich hard coden, was in Basic ziemlich schwierig ist wegen der vielen Anführungszeichen und weil StarBasic Zeilenfortsetzungen (eine Code-Zeile auf mehrere umbrechen) unnötig kompliziert macht.
Jeder Anfänger hat mit hart kodiertem SQL und mit ThisDatabaseDocument/ThisComponent die allergrößten Probleme. Daher rate ich dazu, solche Makros von Formularelementen aufzurufen und hinreichend gute Dokumentation auf dem Form-Dokument dazu zu schreiben. Man kann für die SQL-Schaltfläche jedes bestehende Formular benutzten oder in diesem Fall einfach ein neues Formular erstellen, das logische Hauptformular an eine beliebige Tabelle binden und als einziges Kontrollelement die Schaltfläche mit dem SQL hinzufügen. Das Recordset des Formulars ist ja in diesem speziellen Fall egal. Das Formular und seine Schalftläche liefern alles, was das Makro zum laufen braucht.

WOW!! :smiley: VIIIIELEN HERZLICHEN DANK! Das ist mir sehr hilfreich!

Man schlägt es nach, indem man zuerst das Anwendungsprogramm zu beherrschen lernt und sich dann durch die Objekthierarchie der UNO API hangelt. Zu letzterem dienen Extensions wie MRI oder XRay.

Kannst Du mir vielleicht - das wäre aber wirklich das Sahnehäubchen - eine Unterlage empfehlen, in der das ganze gut strukturiert beschrieben ist? Gibts da ein Standardwerk?

https://web.archive.org/web/20231002132402/https://berma.pagesperso-orange.fr/Files_en/XrayTool60_en.odt

1 Like