Abfrage einer MS SQL 2008 DB mit Autoit

  • Hallo zusammen,


    wir fragen bei uns in der Firma diverse MS SQL Datenbanken mit SQirrel ab. Ich würde jetzt gerne für ein paar Anwender eine kleine GUI machen, wo Sie vordefinierte SELECTS durchführen können, d.h. Sie können nix kaputt machen und müssen sich auch nicht mit SQL Statements auskennen.


    Ich bin jetzt nur etwas verunsichert, da es einige MSSQL.au3 UDFs im Netz gibt, aber auch eine SQLite UDF im Standard dabei ist.
    Welche UDF sollte man für eine MSSQL Datenbank aktuell verwenden ?


    Danke


  • ich nutze die, ich hatte auch schon ene komplettere gefunden aber diese UDF reicht wenn man weiß wie es mit TSQl umzusetzten ist.
    Btw. was hat den mysql mit MSSQl zu tun? Wenn Du an ein MS DBMS willst würde ich vom Kopf her die mssql udf nutzen, ist doch irgendwie logisch,oder. :)


    Gruß Dietmar

    Achtung Anfänger! :whistling:


    Betrachten des Quellcodes auf eigene Gefahr, bei Übelkeit,Erbrechen,Kopfschmerzen übernehme ich keine Haftung. 8o

  • Ich habe eine der MSSQL UDF´s geschrieben (siehe Signatur) aber Dietmar hat recht, das was er dort gepostet hat, ist alles was man benötigt.
    Meine UDF basiert quasi auch nur auf diesen 3 Befehlen, nur habe ich eben auch Wrapper für andere Funktionen geschrieben.


    Es kommt eben drauf an, was du genau machen willst.
    Ich habe in meiner UDF zum Beispiel eine Funktion, um Daten abzufragen und direkt als Array zurück zu liefern. Natürlich kannst du das aber auch einfach selbst mit den 3 Funktionen zusammen basteln :)

  • OK, es geht weiter :-)
    Ich habe jetzt angefangen eine GUI zu bauen. Die Verbindung zu den unterschiedlichen MSSQL Servern steht, jedoch bin ich leider mit den ADO noch gar nicht fit, sodass ich gerade vor folgendem Problem stehe.
    Auf Grund von verschiedenen Comboboxen und Inputfeldern wird über einen Button eine Suche ausgelöst, die auch funktioniert
    Hier mal der Code


    Jetzt ist es ja laut dem "nicht von mir stammenden Code" so, das ich mit $rs.Fields("BEGLEITSCHEIN_ID").value immer nur auf einen definierte Wert aus der Datenbanktabelle greifen kann.
    Sicherlich kann ich via SQuirell mir die Tabelle im Vorfeld anschauen und dann das Script anpassen, jedoch würde ich gerne eine Möglichkeit haben ein

    SQL
    select * from MEINE_DB_Tabelle

    durch zu führen, und erst mal alles zu sehen, d.h ohne

    SQL
    where ....

    Bedingung.


    Wie stelle ich das mit dem ADO an ?


    2. Möchte ich dann gerne das Ergebnis runterstrippen auf die Werte, die mich interessieren und diese dann in der GUI ausgeben. Was für ein Controll macht hier am meisten Sinn ?
    Also die Ausgabe anstelle von "ConsoleWrite" in ein Controll,


    vielen Dank


    Kleine Nachtrag.


    Habe jetzt folgendes versucht:


    ConsoleWrite($rs.Fields & " = " & $rs.value & @CRLF)oderConsoleWrite($rs.Fields.x.name & " = " & $rs.Fields.x.value & @CRLF)
    (habe ich von hier)
    Aber entweder verstehe ich das falsch, oder ich hab einfach was falsch gemacht

  • 2. Möchte ich dann gerne das Ergebnis runterstrippen auf die Werte, die mich interessieren und diese dann in der GUI ausgeben. Was für ein Controll macht hier am meisten Sinn ?
    Also die Ausgabe anstelle von "ConsoleWrite" in ein Controll,


    Für Tabellen eignen sich prinzipiell ListView Controls, da du hier wunderbar 2D-Strukturen, also mehrere Spalten und Zeilen darstellen kannst. Wenn dich hingegen nur die Inhalte von jeweils einer Tabellenspalte interessieren ist eine Combobox oder Listbox vielleicht die richtige Wahl. Prinzipiell könnte man auch multiple Comboboxen für die Darstellung mehrerer Spalten verwenden, jenachdem was du bezwecken willst.


    Was die Informationen der kompletten Tabelle angeht... du kannst zum einen die Anzahl der Spalten als auch deren Namen aus der Ergebnistabelle ermitteln. Mit diesen Informationen kannst du dann die Daten strukturiert auslesen.


    Code
    colCount=recObj.fields.count ' to retrieve the no. of columns in recordset
    msgbox(colCount)
    For i=0 to colCount-1
    msgbox(recObj(i).name) 'to find the coumn names of recordset
    Next


    Siehe auch hier: http://www.geekinterview.com/question_details/30641

  • Hi misterspeed,


    erst mal Danke für die Info. Habe jetzt ein wenig rumprobiert. Zum testen bin ich mal auf eine andere Tabelle mit wenige Einträgen gegangen.
    Mein Code:
    $rs.Open("SELECT * FROM TEILNEHMERTYP", $conn, 1, 3)
    MsgBox(0,"RecordCount",$rs.RecordCount)
    For $i=0 to $rs.RecordCount - 1
    MsgBox(0, "Name", $rs($i).name)
    Next
    So sieht die Tabelle im Squirell gerade aus:
    [Blockierte Grafik: http://www.hasenmueller.de/files4forum/Bild-004-2013-05-03.jpg]
    d.h. 3 Spalten a 5 Reihen.
    Über das Script bekomme ich via MsgBox(0,"RecordCount",$rs.RecordCount)raus, das es 5 Reihen sind.
    Die 3 Spalten sind meine Unbekannte, die ich gerne wissen will.
    Mit dem Teil For $i=0 to $rs.RecordCount - 1
    MsgBox(0, "Name", $rs($i).name)
    Nextbekomme ich dann die 3 Spaltenname angezeigt, aber auch 2 leere Messageboxen, von daher finde ich das Suboptimal.
    Ich habe in Squirell jedoch folgendes entdeckt
    [Blockierte Grafik: http://www.hasenmueller.de/files4forum/Bild-005-2013-05-03.jpg]
    Gibt es eine Möglichkeit die Metadaten abzufragen. Hier steht ja eigentlich alles drin, was mich erst mal interssiert.

  • Zitat

    Gibt es eine Möglichkeit die Metadaten abzufragen. Hier steht ja eigentlich alles drin, was mich erst mal interssiert


    Genau das machen die beiden Funktionen "fields.count" bzw. "(index).name". ;)


    Ist doch klar, dass du 2 leere Msgboxen bekommst, weil es keine spalte 4 und 5 gibt. Im moment machst du deine SELECT Abfrage und durchläufst alle REIHEN (5 Stück) des Ergebnises, das hat prinzipiell nichts mit den Spalten zu tun.
    Du musst vor deiner Auswerung des eigentlichen SELECT erstmal schauen wieviele Spalten es gibt und bei Bedarf auch wie diese heißen. Danach kannst du weitere SELECT Abfragen machen und sofern notwendig auch dynamisch durch die zuvor ausgelesenen Spaltennamen erzeugen.


    Ich habe zwar weder eine DB noch die benötigten Includes, aber theoretisch sollte das so ausschaun:

    $rs = ObjCreate("ADODB.RecordSet")


    $rs.Open("SELECT * FROM TEILNEHMERTYP", $conn, 1, 3)


    $spalten = $rs.fields.count ; die anzahl der Spalten ermitteln
    for $i = 0 to $spalten-1
    consolewrite("Spalte " & $i & ": " & $rs($i).name & @crlf) ; die Namen der Spalten auslesen
    next


    ; dein SELECT Ergebnis zeilenweise durchgehen und ausgeben
    While Not $rs.EOF
    ; alle Werte aller Spalten der aktuellen Zeile ausgeben
    for $j = 0 to $spalten-1
    consolewrite($rs.fields($j).value & @TAB)
    next
    consolewrite(@crlf)
    $rs.MoveNext
    wend
    $rs.Close

  • wie kann mann eigentlich eine Leere rückgabe abfangen?



    $vorhanden = $adCN.Execute('Select ....... ')
    $vorhanden_array = $vorhanden.GetRows

    Bei dem obigen code wird das Script beendet mit dem Fehlercode:


    The requested action with this object has failed.


    Kennt jemand eine Lösung?

  • So Freunde der Nacht, es geht langsam aber sicher weiter :-)


    Da ich kein ADO Experte bin, bitte ich hier mal um Hilfe.


    Kurzfassung:
    $conn = ObjCreate("ADODB.Connection");
    $DSN = .... "Anmeldedaten am Server";
    $conn.Open($DSN) ; Verbindung wird aufgebaut


    $rs = ObjCreate("ADODB.RecordSet");
    $rs.Open("SELECT * FROM BEGLEITSCHEIN where BGSNR ='" & $Suchbegriff & "';", $conn); ab hier habe ich mein Suchergebnis


    If $rs.RecordCount Then
    While Not $rs.EOF
    ;..... hier bestücke ich die Listview
    Ich habe jetzt das Problem, das ich innerhalb der While Not Schleife einen zweite SELECT machen muss, wo ich eine ID aus dem ersten SELECT in einer anderen Tabelle suchen will.
    Alle bisherigen Versuche gingen bisher schief.


    Ich darf ja das Ergebnis von $rs.Open("SELECT * FROM BEGLEITSCHEIN where BGSNR ='" & $Suchbegriff & "';", $conn); ab hier habe ich mein Suchergebnis nicht verändern


    Wie stellt man dass den an ?


    Gruss und Danke

  • pass doch die query so an das direkt das Ergebnis zurückkommt, man kann die ja auch kombinieren ;)'


    select telemnr, bez from tmmodul where telemnr IN (select telemnr from tminfo where infonr in(select infonr from firma) )


    g Dietmar

    Achtung Anfänger! :whistling:


    Betrachten des Quellcodes auf eigene Gefahr, bei Übelkeit,Erbrechen,Kopfschmerzen übernehme ich keine Haftung. 8o

  • Sorry Dietmar,


    das check ich nicht. Ist das sowas ähnliches wie ein Join ?


    Ich will einfach einen 2. eigenständigen Select machen, weiß aber nicht, ob ich hier nochmals ein 2. Objekt öffnen muss, oder wie man hier vorgeht.

  • eher subselect


    http://www.software-templ.com/…es/db2006/Manuskript3.pdf


    Der Vorteil ist, das Du Dich hinterher nicht mit zuviel Infos rumplagen musst, also Du im Vorfeld per SQL schon sauber filtern kannst.
    Manchmal bzw. oft kommt ja nicht nur ein Wert zurück, also musst Du die Ergenismenge in einer Schleife wieder durchlaufen. Also hast Du schnell unnötig Mehraufwand.


    Gehen wird beides, eleganter ist es sicher per sql die Sachen zusammen zu suchen da tsql auch von Hause aus recht mächtig ist.
    Wenn Dir das Getippe zuviel ist kannst Du evtl. ja auch ne View anlegen und nur noch den Inhalt per select holen.


    Gruß Dietmar

    Achtung Anfänger! :whistling:


    Betrachten des Quellcodes auf eigene Gefahr, bei Übelkeit,Erbrechen,Kopfschmerzen übernehme ich keine Haftung. 8o

    Einmal editiert, zuletzt von Dietmar ()

  • Würde dir auch nahelegen das gleich in das erste Select mit reinzupacken, aber wenn dir das zu verschachtelt und kompliziert ist spricht ja nix dagegen ein zweites recordset object für eine weitere Abfrage anzulegen. Mal an deinem Beispiel orientiert:



    $conn = ObjCreate("ADODB.Connection");
    $DSN = .... "Anmeldedaten am Server";
    $conn.Open($DSN) ; Verbindung wird aufgebaut


    $rsMain = ObjCreate("ADODB.RecordSet");
    $rsMain.Open("SELECT * FROM BEGLEITSCHEIN where BGSNR ='" & $Suchbegriff & "';", $conn); ab hier habe ich mein Suchergebnis


    If $rsMain.RecordCount Then
    While Not $rsMain.EOF
    ;..... hier bestücke ich die Listview
    $rsSub = ObjCreate("ADODB.RecordSet");
    $rsSub.Open("SELECT * FROM AndereTabelle where irgendeineIDspalte = " & $rsMain.fields("ID").value & ";", $conn)

    If $rsSub.RecordCount Then
    While Not $rsSub.EOF
    ; hier dann wieder rsSub Ergebnis auslesen
    wend
    endif
    wend
    endif



    In deinem Fall ist aber doch eigentlich ein join genau das was du willst oder nicht? Also doch alles problemlos über eine SQL Abfrage machbar:


    $rsMain.Open("SELECT * FROM (BEGLEITSCHEIN bg, AndereTabelle at) where bg.BGSNR ='" & $Suchbegriff & "' AND bg.ID = at.irgendeineIDspalte ;", $conn); ab hier habe ich mein Suchergebnis

  • Hallo zusammen,


    vielen Dank für Eure Bemühungen. Das ist mal wieder ein klassisches Layer 8 Problem :-) (knock knock). Mein Kollege meinte auch, das ich das mit eine "left join" abbilden kann, aber


    1.) bin ich in ADO nicht fit
    2.) in SQL Statements genauso wenig


    d.h. ich muss mich mit meinen kleinen Knowhow begnügen.


    Momentan habe ich es so gelöst, das ich die 2. Selectabfrage in eine eigene Function gestellt habe, welche ich dann aufrufe. Somit bin ich offen für weitere Selects, die vermutlich noch kommen. Bestimmt nicht die feinste Art, aber für mich tut's das.


    Jetzt habe ich aber ein kleines kosmetisches Problem.


    Erst mal mein Code:


    In Zeile 9 erstelle ich eine Listview.
    Wenn ich jetzt z.B. eine Abfrage auf "Begleitschein ID" (Zeile 109) mache, dann wird ja in Zeile 133 bis 144 die Spaltenname der Listview erzeugt. Soweit alles gut.
    Sobald ich jedoch dann von der Abfrage "Begleitschein ID" auf die Abfrage "Begleitscheinnummer" (Zeile 15) wechsle, werden von Zeile 32 bis 43 die Spaltennamen neu aufgebaut.
    Es ändert sich eigentlich auch nur die Reihenfolge der ersten beiden Spalten, der Rest bleibt gleich. Auch bis hierher passt es - fast
    Mir ist dann aufgefallen, das die "neuen" Spaltennamen etwas komisch aussehen (zusammengeschrumpft). Nach kurzer Analyse viel mir auf, das wenn ich mit der Maus über den Namen von Spalte 1 fahre, der "alte" Spaltenname von der Abfrage auf "Begleitschein ID" wieder zum Vorschein kommt.


    Ich habe dann die Hilfe mal durchstöbert und wollte jetzt folgendes machen. Bevor ich die Listview aufbaue, wollte ich prüfen, ob eine alte Listview existiert. Wenn ja, dann "zerstören".
    Dafür war eigentlich Zeile 4 bis 7 gedacht. Auf Grund des Consolwrite in Zeile 6 wollte ich prüfen, ob die If Abfrage wahr ist, was aber nicht der Fall ist, d.h. meine Listview welche ursprünglich in Zeile 9 erstellt wurde, wird nicht zerstört.


    Warum wird die Listview nicht gefunden, bzw. was ist der richtige Ansatz, damit sowas nicht passiert.


    vielen Dank und vorab schon mal einen schönen Vatertag :party:

  • Ich glaub ich bin auf dem Holzweg ....


    Habe jetzt mal mit
    Local $listview
    $rs = ObjCreate("ADODB.RecordSet")
    ;~ If $listview Then
    ;~ _GUICtrlListView_Destroy($listview)
    ;~ ConsoleWrite("Listview zerstört" & @CRLF)
    ;~ EndIf
    _GUICtrlListView_Destroy($listview)
    $listview = GUICtrlCreateListView("", 20, 190, $GUIWidth - 40, 520);,$LVS_SORTDESCENDING)
    $iColor = RGB2BGR(0xFFFFCC) ; Hintergrundfarbe Smartgelb
    _GUICtrlListView_SetBkColor($listview, $iColor)
    _GUICtrlListView_SetTextColor($listview, $CLR_BLACK)
    _GUICtrlListView_SetTextBkColor($listview, $iColor)
    versucht die Listview ohne Abfrage zu löschen (Zeile 7)
    Das Ergebnis ist jedoch gleich, d.h. die alten Spaltennamen tauchen immer wieder auf.
    Ich denke hier "denke ich falsch" ...

  • Erstmal deklarierst du die Variable Listview lokal, das hat automatisch zur Folge, dass deren Inhalt verloren ist sobald du die Funktion verlässt. Bem nächsten Aufruf der Funktion ist die Control ID des "alten" Listviews also weg und das Listview kann auch nicht mehr gelöscht werden.


    Lösung:


    Deklariere deine Variable einmalig global (ausserhalb einer Funktion). Sobald du die Funktion suche() aufrufst löschst du das Listview (es ist egal ob überhaupt eins existiert oder die Variable noch leer ist) und erzeugst es dann neu. Achte darauf, dass die Variable $Listview nicht mehr in der Funktion deklariert wird (weder lokal noch global), da du durchs Deklarieren zusätzlich den Inhalt löschst. Nun sollte die ID des Listviews wie gewollt immer in der globalen Variable landen.