Posts mit dem Label SQL werden angezeigt. Alle Posts anzeigen
Posts mit dem Label SQL werden angezeigt. Alle Posts anzeigen

Freitag, 6. März 2009

Wie man mit Visual Studio 2008 Express Edition (VB.net) eine Verbindung zu einem entfernten SQL Server herstellt

Der Express Edition von Microsofts Visual Studio fehlen leider die Tools um eine Verbindung zu einer entfernten SQL-Datenbank herzustellen. Man kann mit dem Assistenten zwar eine Verbindung zu einer lokalen Instanz herstellen, aber wir wollen ja eine Client-Server Datenbankanwendung basteln. Und zwar "für lau".

Deswegen hier eine kurze Anleitung, wie ich ohne viel Drumherum eine entsprechende Verbindung herstellen kann, ohne die entsprechenden Tools und Assistenten.

Nachdem wir ein neues Projekt (Windows Forms Anwendung) angelegt haben,
basteln wir uns zunächst einmal ein Formular namens frmStart, darauf kommt ein Textfeld Namens txtFeld. Das wars dann auch schon fürs Erste mit Formular basteln.

Ich setze in diesem Beispiel der EInfachheit halber vorraus, dass ihr einen funktionierenden SQL Server im Netz habt, bei dem (falls SQL Express) Remote Connections aktiviert sind!

hier der Code:


Public Class frmStart

Private Sub frmStart_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

Dim cmdSQL As SqlClient.SqlCommand
Dim asyncResult As System.IAsyncResult
Dim returnValue As SqlClient.SqlDataReader
Dim strSQL As String

Using conSQL As New SqlClient.SqlConnection("Data Source=[SERVERNAME/INSTANZ];Initial Catalog=[DATENBANKNAME];User Id=[USERNAME];Password=[PASSWORT];Async=true")
conSQL.Open()
strSQL = "[SQLSTRING]"
cmdSQL = New SqlClient.SqlCommand(strSQL, conSQL)
asyncResult = cmdSQL.BeginExecuteReader()
returnValue = cmdSQL.EndExecuteReader(asyncResult)
If returnValue.Read() Then
Me.txtFeld.Text = returnValue.Item("[FELDNAME]")
End If
End Using
End Sub
End Class




Was bedeutet das nun im Einzelnen?

Die Variablendeklaration:

Dim cmdSQL As SqlClient.SqlCommand
Dim asyncResult As System.IAsyncResult
Dim returnValue As SqlClient.SqlDataReader
Dim strSQL As String

  • cmdSQL ist das Commandobjekt, also der Behälter für unseren SQL-Befehl
  • asyncResult gibt Auskunft über den Status der asynchronen Operation (neu in ADO.net 2.0 - zum Thema asynchrone/synchrone Operationen bitte Googel bemühen, das führt hier zu weit)
  • returnValue ist das Readerobjekt, dass nachher unser Resultset enthalten soll
  • strSQL ist lediglich die Stringvariable für unseren SQL-Befehl
Das Verbinden mit dem Datenbankserver:

Using conSQL As New SqlClient.SqlConnection("Data Source=[SERVERNAME/INSTANZ];Initial Catalog=[DATENBANKNAME];User Id=[USERNAME];Password=[PASSWORT];Async=true")
conSQL.Open()


  • Using [Connection-Variable] As New SqlClient.SqlConnection([Connection String]) sorgt dafür, dass wir die mit dem Connection-String definierte Verbindung innerhalb der Using-Anweisung verwenden. Wie der Connection String aussehen soll? --> http://www.connectionstrings.com/ Der Connectionstring muss die Anweisung "Async=true;" enthalten, damit das mit der asynchronen Operation funktioniert!
  • conSQL.Open() öffnet die Verbindung schlussendlich
Befehl senden/Resultat empfangen:

strSQL = "[SQLSTRING]"
cmdSQL = New SqlClient.SqlCommand(strSQL, conSQL)
asyncResult = cmdSQL.BeginExecuteReader()

  • strSQL = "..." hier definieren wir unseren SQL String, also SELECT * FROM tblIrgendwas
  • dann wird dem Command-Objekt der SQL String und die Connection an die der Befehl gehen soll übergeben
  • und wir weisen den Status der Async-Operation der zuvor definierten Variable zu
Anzeigen der Daten:

returnValue = cmdSQL.EndExecuteReader(asyncResult)
If returnValue.Read() Then
Me.txtFeld.Text = returnValue.Item("[FELDNAME]")

  • unserem Readerobjekt "returnValue" weisen wir das Resultat der Abfrage zu ...
  • ... dann, wichtige Sache, erst wenn das Readerobjekt fertig gelesen hat...
  • ...weisen wir dem Textfeld einen Wert zu! Wenn dieses if fehlen würde, kommt es höchstwarscheinlich zu einem Fehler, da das Programm schneller in der nächsten Zeile ist, als dass der Server das Resultat geliefert hat! Es kommt dann der Fehler:
    "Um eine indizierte Eigenschaft auszuwerten, muss die Eigenschaft qualifiziert sein, und die Argumente müssen explizit vom Benutzer bereitgestellt werden." (Item) und
    "Ungültiger Leseversuch, wenn keine Daten vorhanden sind." (Message)
und das Gedöns ...

End If
End Using
End Sub
End Class

  • alles wieder zumachen, was wir aufgemacht haben
Dann F5 drücken und freuen, dass in dem Textfeld der Inhalt des Feldes angezeigt wird, dass ihr abgefragt habt. tata!

Automatisieren von Backups mit SQL Server Express Edition

Der (sonst absolut fantastischen) Express Edition des SQL Servers von Microsoft fehlen einige Features der teuren Versionen, so zum Beispiel der Agent für das automatische Ausführen immer wiederkehrender Tasks (e.g. Backups).
Um trotzdem regelmäßig automatische Backups machen zu können gibts verschiedene Möglickeiten. Ich nutze zum Beispiel ein kleines Tool namens SQLScheduler, dass zu vorgegebenen Zeiten SQL-Befehle ausführt und bei Erfolg und/oder Fehlschlag Mails verschicken kann.

Es gibt aber natürlich auch Mittel und Wege, komplett mit Windows/SQL Server Bordmitteln allein eine entsprechende Lösung zu erstellen:

mit VBScript/Windows Scheduler

mit SQLCMD und Windows Scheduler

mit SQL Server Service Broker

Viel Spass beim Backuppen (und nicht vergessen master und msdb mit zu sichern ;)

Donnerstag, 5. Februar 2009

MS SQL: Ausgeben der Parameter einer gespeicherten Prozedur im wiki-Format

Wie schon in meinem vergangenen Post hier wieder ein kleines Skript, dass eine wiki-Tabelle ausgibt, diesmal die Parameter einer gespeicherten Prozedur, inklusive Datentyp und Ausgabeparameter (true/false)

DECLARE @object_id int

SET @object_id =
(SELECT object_id FROM sys.procedures
WHERE Name = '[StoredProcedureName]')

-- Parameter

SELECT '{| class="wikitable"
|+ Parameter
! Name
! Zweck
! Datentyp
! Ausgabeparameter?'

UNION

SELECT '|-
| ' + sp.name + '
|
| ' + st.name + '
| ' + CAST (sp.is_output as nvarchar(1))
FROM
sys.parameters sp
INNER JOIN
sys.types st
ON
sp.system_type_id = st.system_type_id
WHERE
@object_id = object_id

UNION

SELECT '|-
|}'


(was ne ekelhafte Arbeit, den Quelltext jedes mal von Hand in den Farben wie im Management Studio zu formatieren! Notiz an mich selbst: Skript dafür basteln :D)

Dienstag, 3. Februar 2009

MS SQL: Ausgeben einer Tabelle im wiki-Format

Will man (wie ich im Moment) eine MS SQL-Datenbank in einem wiki dokumentieren bietet sich folgendes Skript an, dass ich soeben bastelte:

SELECT '{| class="wikitable"
|+ Spalten
! Name
! Zweck
! Datentyp
! Beispieldaten'

UNION

SELECT '|-
| ' + name + '
|
|
| ' FROM syscolumns
WHERE ID = (SELECT id FROM sysobjects WHERE name='{[Tabellenname]')

UNION

SELECT '|-
|}'

Es gibt die Spalten der Tabelle so aus, dass man das Resultset direkt aus seinem Ergebnisfenster in das wiki-Editorfenster kopieren kann =)

Freitag, 23. Januar 2009

Wie man einen Apache Webserver mit PHP und mySQL aufsetzt (LAMP Server die 1te)

Ich wollte hier in der Arbeit einen Apache mit allem drum & dran aufsetzen um zu Dokumentationszwecken ein wiki nutzen zu können.
Nun kommt das ja aus der Unix/Linux Welt (und ich, böse böse, nutz hier Fenster2000), sprich rumhantieren mit Konfigurationsdateien und umherkopieren von Bibliotheken (anstatt durch Wizards klicken wie bei Fenster) war angesagt. Natürlich hat man so die totale Kontrolle über alle Optionen und kann diese schnell und theoretisch auch komfortabel einstellen.
Aber: Wenn man das noch nie gemacht hat, kann einem schon mal schwindlig werden. Man könnte sagen, der Ottonormalverbraucher sollte eigentlich eh keinen Webserver aufsetzen, deswegen ist das auch gut so und vielleicht sollt ich auch lieber Linux nutzen, aber das führt jetzt zu weit.

Wieauchimmer - ich möchte euch einen Link nicht vorenthalten der meinen day gemaked hat:

Setting up your first web server on windows with Apache, PHP and MySQL

Und im Gegensatz zu meinem Nahezu-Nervenzusammenbruch hab ich doch tatsächlich das Teil zum Laufen bekommen. Hooray!

Freitag, 1. August 2008

XML, XSL, XPath

Ich bearbeite gerade mein erstes Datenbankprojekt, das XML beinhaltet. Sehr spannend.

Ziel soll es sein, eine WHERE Klausel für einen SQL-String als XML-Dokument zu erstellen, dieses in einem TreeView-Steuerelement darzustellen und später die Klausel aus dem XML-File zu generieren.
Als schwierig stellt sich momentan heraus, in dem Treeview nur bestimmte Elemente des XML-Files darzustellen. Logischwerweise möchte ich in dem TreeView nur für Endanwender angenehm zu lesende Kriterien wie "Geburtsdatum größer gleich 1.1.1980" stehen haben anstatt tblKandidaten.DOB >= '#1980-01-01'.
Das XML-File enthält also für Klauseln (Verknüpfung der darunterliegenden Elemente mit AND oder OR) und die Kriterien ([Tabelle].[Feld] [operator] [Wert]) jeweils 2 Felder: Anzeigetext und SQL-Code. Angezeigt werden soll logischerweise nur der Anzeigetext.

Das gestaltet sich gar nicht so einfach, wie es sich möglichwerweise anhört. Seit dem MSXML3 gibt es die Möglichkeit XPath auf das Dokument anzuwenden, quasi eine Abfragesprache für das Dokument. Das Ergebnis ist allerdings eine flache Liste, die Hierarchie ist dahin. Man müsste also rekursiv jede Ebene einzeln nach den gesuchen Elementen abfragen und das TreeView füllen.

Hat bisher noch nicht geklappt, diverse kleine Stolpersteine verhindern den Erfolg.
Eine wietere Möglichkeit, die sich nach Lektüre diverser Internetseiten aufgetan hat, ist das XML-Dokument mithilfe von XSLT in eine weiteres XML-Dokument zu transformieren, dass nur die gewünschten Elemente enthält und damit ganz einfach angezeigt werden kann.

eine Lösung steht noch an. Der usenet-thread zu dem Thema ist hier zu finden.

Mittwoch, 9. Januar 2008

EXISTS vs. IN

Ich hatte hier eine Abfrage in einer gespeicherten Prozedur nach dem Schema

INSERT INTO Tabelle1
SELECT DISTINCT Spalte1, Spalte2, Spalte3
FROM Tabelle 2
WHERE Spalte3 NOT IN
(SELECT Spalte3b FROM Tabelle1);

Also nimm alle Datensätze aus Tabelle2, deren Spalte3 keine Entsprechung in Spalte3b der Tabelle1 hat und füge diese in die Tabelle 1 ein. Also um sicher zu stellen, dass jeder Datensatz nur ein mal in Tabelle 1 eingefügt wird. Hat bisher prima funktioniert. Nur heute war das einzufügende Resultset leer, obwohl nachweislich Daten da waren, die das Kriterium erfüllten.

Rätsel, Rätsel, Recherchier, Recherchier und siehe da: Die gute alte NULL war mal wieder schuld an allem. Ist in dem Resultset der Unterabfrage (SELECT Spalte3b FROM Tabelle2) eine NULL enthalten, so führt das zum "dritten" Booleanwert unknown, weshalb die gesamte Bedingung falsch wird.
Besser man nutzt EXISTS, was die NULL-Werte ignoriert:


INSERT INTO Tabelle1
SELECT DISTINCT Spalte1, Spalte2, Spalte3
FROM Tabelle2
WHERE NOT EXISTS
(SELECT * FROM Tabelle1 WHERE Tabelle1.Spalte3b = Tabelle2.Spalte3);

et voila!

entsprechender Thread bei theScripts

Montag, 8. Oktober 2007

Verknüpfte Abfragen SQL-Server - Index Server


Es soll eine Abfrage ausgeführt werden, die Daten aus der Datenbank und Dateien durchsucht. Es gibt sicher ne Menge Möglichkeiten, das zu realisieren. Ich hab mich für folgende entschieden und finde sie ziemlich elegant:

Die Abfrage des Dateiinhaltes übernimmt der in Windows Server integrierte Index Service (oder Index Server). Dieser kann auf verschiedene Art und Weise abgefragt werden z.B. über eine Web-Oberfläche und über ADO.
Man kann den Index Server auch als Verbindungsserver im SQL Server registrieren und so SQL-Queries mit Index-Server Queries kombinieren! Genauso hab ichs dann auch gemacht:

Zunächst muss man die Registrierung durchführen:

EXEC sp_addlinkedserver '[Servername]', '', 'MSIDXS', 'Web', NULL, NULL

Wobei [Servername] logischerweise der Name des Server ist, auf dem der Indexservice läuft. Web ist der Name des Katalogs, der heisst standardmäßig Web, wenn Ihr keinen neuen angelegt oder denh Alten umbenannt habt. MSIDX ist der Name des Dienstes.

Dann könnt Ihr schon loslegen, je nachdem wie die Berechtigungen bei euch aussehen:

DECLARE @strSQL as nvarchar(400)

SELECT @strSQL= 'select FileName, path, size, vpath from scope() where contains
('SELECT @strSQL=@strSQL +CHAR(39)+ CHAR(39)+ [Suchbegriff] + CHAR(39)+ CHAR(39)+')'

SELECT @strSQL='SELECT * FROM
OPENQUERY([Servername],'+ CHAR(39) + @strSQL + CHAR(39) +')
EXEC sp_executesql @statement = @strSQL

Wenn Ihr, wie ich, eine kombinierte Abfrage über Daten und Dateien durchführen wollt, könnt Ihr natürlich auch einen JOIN über beide Server durchführen, eine entsprechende Spalte vorrausgesetzt. Bei mir ist das der Dateiname.

Für mehr Details, empfehle ich diesen Thread bei Google Groups, aus dem ich auch meine Infos hab. Dort steht auch, wie man ggf. einen Login für den Verbindungsserver erstellt.