C# SQL 2005 Express ExecuteNonQuery wird nicht unterstützt?

roker002

Commander
Registriert
Dez. 2007
Beiträge
2.073
Hmm habe 2 Testserver. Der einer ist SQL 2008 Enterprise (Dev Edition) und der anderer ist 2005 Express. Auf dem Express kann ich kein ExecuteNonQuery ausführen. Gibt es da eine Einschränkung auf dem Server selbst?
 
Doch funktioniert. Ich setze für meine Projekte fast nur SQL 2005 Express ein mit ExecuteNonQuery. Da muss es etwas anderes haben. Wie lautet denn das SQL Statement bzw. gehen normale Selects?
 
Ist ein Connect zum SQLServer 2005 Express möglich?
Wie lautet das Commando was du mit ExecuteNonQuery ausführen möchtest?
Sind für den Connection User die Rechte für INSERT, UPDATE, DELETE auf der Tabelle gesetzt? (Vorausgesetzt du möchtest ein INSERT, UPDATE oder DELETE ausführen)
Verwendest du System.Data.SqlClient ?
Verwendest du für die Connection das Integrated Login (sprich Windows Authentifizierung) oder SqlServer Login?
Wird eine Exception ausgelöst und wenn ja welche? Was steht in Exception.Message?

Habe selber diverse Programme für SQLServer 2005 Express mit .Net Framework gemacht ohne das ein solches Problem je aufgetaucht wäre.
 
Zuletzt bearbeitet:
Es werden die UserID und PW für die verbindung genutzt. Es sollte daher auch kein problem sein mit Authentifizierung.

aah ja ich sehe es! also kann man bei SQL 2005 Express nur mit eine Abfrage gleichzeitig arbeiten? und der 2008er unterstützt die mehrfachabfrage in einen Command String? Teilt der SQL Manager viele Abfragen in die einzelne auf?

Muss man noch irgendwas wissen bevor man weiter programmiert?

Code:
[COLOR="Red"]System.Data.SqlClient.SqlException: Unterabfragen sind in diesem Kontext nicht zulässig. Es sind nur Skalarausdrücke zulässig.[/COLOR]
   bei System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection)
   bei System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection)
   bei System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj)
   bei System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj)
   bei System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString)
   bei System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async)
   bei System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, DbAsyncResult result)
   bei System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(DbAsyncResult result, String methodName, Boolean sendToPipe)
   bei System.Data.SqlClient.SqlCommand.ExecuteNonQuery()
   bei System.Windows.Forms.Control.OnClick(EventArgs e)
   bei System.Windows.Forms.Button.OnClick(EventArgs e)
   bei System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)
   bei System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
   bei System.Windows.Forms.Control.WndProc(Message& m)
   bei System.Windows.Forms.ButtonBase.WndProc(Message& m)
   bei System.Windows.Forms.Button.WndProc(Message& m)
   bei System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
   bei System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
   bei System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
 
Zuletzt bearbeitet:
also kann man bei SQL 2005 Express nur mit eine Abfrage gleichzeitig arbeiten? und der 2008er unterstützt die mehrfachabfrage in einen Command String?

Sorry, aber es ist soweit nicht richtig hinsichtlich SQLServer 2005. Um dir Genaueres sagen/zeigen zu können, bräuchte ich den SQLBlock den du der SqlCommand.CommandText Eigenschaft zuweist...

Prinzipiell kommt auch der SQLServer 2005 mit mehreren Abfragen klar und kann dann entsprechend mehrere Resultsets zurückgeben. Ebenso ist es möglich einen T-SQL Block mit mehreren Anweisungen über ExecuteNonQuery zur Datenbank zu senden.

Deswegen sei bitte so gut und poste mal den SQLBlock... Ich bin gespannt wie ein Flitzebogen, was des Rätsels Lösung ist. Kann es sein das du eine Stored Procedure aufrufst die mehrere Resultsets zurück gibt? z.B. SP_HELP(object_name)
 
Zuletzt bearbeitet:
Code:
                       "if not exists(select * from [staedte] where [staedte].[stadt_name]=@City)" +
                        "BEGIN " +
                            "INSERT INTO [staedte] VALUES(@City) " +
                        "END " + 
                        "if not exists(select * from [adresse] where [adresse].[plz_id]=@Zip) " +
                        "BEGIN " +
                        " INSERT INTO [adresse] ([plz_id],[stadtteil],[bundesland],[stadt_id]) " +
                            "VALUES(@Zip,NULL,NULL,(select [staedte].[stadt_id] from [staedte] where [staedte].[stadt_name]=@City)) " +
                        "END " + 
                        "if not exists(select * from [strassen] where [strassen].[strasse]=@Street AND [strassen].[plz_id]=@Zip)" +
                        "BEGIN " +
                            "INSERT INTO [strassen] VALUES(@Zip,@Street) " +
                        "END";

So hab den Query wieder zu einem Zusammengefügt. Es ist eigentlich ein Teil aus der Adressdatenbank. Ich arbeite strickt mit Foreign Keys.
 
Mein Tipp:

Pack den ganzen Block in ein "BEGIN" und "END":

Code:
string sCommand = string.Concat(
  "BEGIN\r\n",
    "if not exists(select * from [staedte] where [staedte].[stadt_name]=@City)\r\n",
    "BEGIN\r\n",
      "INSERT INTO [staedte] VALUES(@City)\r\n",
    "END\r\n", 
    "if not exists(select * from [adresse] where [adresse].[plz_id]=@Zip)\r\n",
    "BEGIN\r\n",
      "INSERT INTO [adresse] ([plz_id],[stadtteil],[bundesland],[stadt_id]) " ,
      "VALUES(@Zip,NULL,NULL,(select [staedte].[stadt_id] from ",
      "[staedte] where staedte].[stadt_name]=@City))\r\n",
    "END\r\n", 
    "if not exists(select * from [strassen] where [strassen].[strasse]=@Street AND [strassen].[plz_id]=@Zip)\r\n",
    "BEGIN\r\n",
      "INSERT INTO [strassen] VALUES(@Zip,@Street)\r\n",
    "END\r\n",
  "END");

Das Carriage Return + Linefeed ("\r\n") am Ende jeder Zeile ist notwendig sonst gibts einen langen String-Wurm den der SQLServer Parser nicht sauber in seine Bestandteile trennen kann. Alternativ kannst du auch nach jedem Befehl (außer BEGIN) ein Semikolon setzen. So wie ich das sehe verwendest du in deiner Version mehrere T-SQL Blöcke die vom SQLServer 2005/.Net Framework dann entsprechend nicht in ExecuteNonQuery verwendet werden können. Durch das BEGIN und END sollte das aber als ein ganzer einheitlicher Block vom DBMS verstanden werden.

Die Foreign Keys sind zur Lösung erstmal nicht relevant und da brauchst du wahrscheinlich auch erstmal nicht drauf zu achten, später bei Performanceproblemen kannst du da auch noch Hand anlegen. Denke aber daran das ForeignKey nicht implizit einen Index anlegt, das musst du dann noch selber erledigen. Mit dem Foreign Key hast du lediglich die Beziehung zw. mehreren Tabellen hergestellt, sodaß die Integrität der Daten in den Tabellen vom DBMS gewährleistet werden kann. Das DBMS weiß aber noch nicht das es die Zugriffe über die FK optimieren soll. Deshalb schön Index draufgelegt und fertig ist der Lack...

Viel Erfolg...
 
du meinst jetzt, ich soll den index selbst vorgeben?
Da wähe das problem mit herausfinden des letzten index. Es kostet eine zusätzlich abfrage.

mit \r\n habe ich auch durchgedacht. ich lasse immer eine freie stelle damit die Strings auch ein leerzeichen dazwischen haben. Ich werde mal morgen den neuen befehl ausprobieren. vielleicht klappt es jetzt. aber ich verstehe immer noch nicht wieso sql 2008 den befehl kann und sql 2005 nicht. klar, die haben teilweise andere engine zum erkennen von abfragen aber so gravierend kann es doch nicht sein, oder?

wegen FK wollte ich nur sagen, weil man sonst nicht sofort erkennt was die 3 abfragen mit einander zu tun haben.
 
du meinst jetzt, ich soll den index selbst vorgeben?
Da wähe das problem mit herausfinden des letzten index. Es kostet eine zusätzlich abfrage.

Verstehe jetzt nicht so wirklich, was du damit meinst. Ich beziehe mich auf die Erstellung der Indizes einer Tabelle ala "CREATE INDEX IX_NAME ON TableName ..." zur Optimierung falls die Abfragen langsam sind. Das sollte man machen, wenn man einen ForeignKey für eine Tabelle angelegt hat. Mal angenommen du hast eine Tabelle mit einer Spalte die als ForeignKey definiert wurde. Dann macht es Sinn einen Index auf genau diese Spalte zu legen. Das hat erstmal nichts mit zusätzlichen Abfragen oder dergleichen zu tun sondern ist nur für die Erstellung der Tabelle wichtig.

mit \r\n habe ich auch durchgedacht. ich lasse immer eine freie stelle damit die Strings auch ein leerzeichen dazwischen haben.
Ist soweit korrekt, außer du hast mehrere SELECT Befehle hintereinander, dann musst du entweder mit \r\n die Befehle voneinander trennen oder du trennst die Befehle durch ein Semikolon. Beides würde zum Ziel führen. Ein einfaches Leerzeichen wird vom Parser nicht zwingend als Trennzeichen zwischen 2 Befehlen erkannt und so könnte u.U. ein fehlerhafter Befehl entstehen.

Wenn ich mir jetzt folgenden Befehl genauer anschaue, dann hast du hier sicher auch ein Problem, das bei deinen SQLServer 2005 auftauchen kann, während der SQLServer 2008 keine Probleme macht (Liegt dann an den unterschiedlichen Daten in den Datenbanken):
Code:
"INSERT INTO [adresse] ([plz_id],[stadtteil],[bundesland],[stadt_id]) " ,
      "VALUES(@Zip,NULL,NULL,(select [staedte].[stadt_id] from ",
      "[staedte] where staedte].[stadt_name]=@City))\r\n"

Anhand des Namens einer Stadt soll die STADT_ID ermittelt werden und einen Eintrag in Adresse gemacht werden, soweit korrekt? Das Problem ist, das in Deutschland und auf der ganzen Welt Namen von Städten nicht wirklich eindeutig sind. zB. existieren in Deutschland mehrere Städte die Münster heißen. Und da liegt auch ein Problem, das nicht sofort ersichtlich wird. Weil meistens der Name eindeutig ist, wird das Subselect auch eine einzige gültige ID ermitteln können. Wenn jetzt mehrere Städte mit dem gleichen Namen existieren, ist das Subselect ungültig, weil die Position des Subselects innerhalb der Spaltenauflistung einer Abfrage immer ein eindeutiges Ergebnis haben muss. (gem. SQLServer / SQL Standard) Deswegen kommt dann auch eine entsprechende Fehlermeldung vom DBMS. Eine mögliche Lösung für dieses Problem wäre das du die PLZ mit in das Subselect aufnimmst um eine eindeutige Bedingung zu generieren.

z.B.
Code:
"INSERT INTO [adresse] ([plz_id],[stadtteil],[bundesland],[stadt_id]) " ,
      "VALUES(@Zip,NULL,NULL,(select [staedte].[stadt_id] from ",
      "[staedte] where staedte].[stadt_name]=@City AND [PLZ]=@Zip))\r\n"

Ebenso fehlt bei "... where staedte].[stadt_name] ..." die führende eckige Klammer. Ergänze das mal als "... where [staedte].[stadt_name] ..."
So wie ich das sehe brauchst du diese eckigen Klammern nicht zwingend, da du eh SQL konforme Bezeichnungen, d.h. keine Umlaute etc., in den Objektnamen verwendest. Das würde aus meiner Sicht die Befehle etwas leichter lesbar machen...

Hoffe das ich deine Fragen beantworten konnte, ansonsten gib mal Info wie es denn nun nach den Änderungen ausschaut...

Happy coding!
 
Zuletzt bearbeitet:
Rossibaer schrieb:
Anhand des Namens einer Stadt soll die STADT_ID ermittelt werden und einen Eintrag in Adresse gemacht werden, soweit korrekt? Das Problem ist, das in Deutschland und auf der ganzen Welt Namen von Städten nicht wirklich eindeutig sind. zB. existieren in Deutschland mehrere Städte die Münster heißen. Und da liegt auch ein Problem, das nicht sofort ersichtlich wird. Weil meistens der Name eindeutig ist, wird das Subselect auch eine einzige gültige ID ermitteln können. Wenn jetzt mehrere Städte mit dem gleichen Namen existieren, ist das Subselect ungültig, weil die Position des Subselects innerhalb der Spaltenauflistung einer Abfrage immer ein eindeutiges Ergebnis haben muss. (gem. SQLServer / SQL Standard) Deswegen kommt dann auch eine entsprechende Fehlermeldung vom DBMS. Eine mögliche Lösung für dieses Problem wäre das du die PLZ mit in das Subselect aufnimmst um eine eindeutige Bedingung zu generieren.

Das mit der Eindeutigkeit der stadtnamen ist gar so geplannt. Es ist wie gesagt, die Information über die Relation zwischen den Tabellen selbst notwendig zu wissen um es zu verstehen. Von mir aus kann es 100te Münster geben. Diese eine Tabelle mit Stadtnamen ist nur ein kleines Teil der größere Tabelle. Wenn du jetzt den Insertbefehl für die Tabelle "adresse" anschaust wirst du es sehen was ich meine. Es ist anhand der PLZ möglich die Stadt in Deutschland genau zu ermitteln. Da jede stadt eine eigene PLZ hat die auch für DE eindeutig ist, so ist die Stadtname nicht vom belangen. Sind es mehrere Münster, so sind diese durch die PLZ eindeutig einzuordnen wo sich diese in DE befinden.

Diese Tabellen sind NF 3 optimiert, hoffe ich zumindest.

das mit der fehlende Klammer... ich habe vorhin nur die DB name ausgeschnitten, die klammer wurde dann vielleicht auch mit weg geschnitten, sonst würde der befehl ja auch nicht funktionieren.

Danke für die Hilfe...


ps: Ich habe jede den Subselecte ausgefiltert. Es funktioniert jetzt alles normal.
 
Zuletzt bearbeitet:
Dann vermute ich mal das die Tabelle staedte auf dem SQLServer 2005 2 mal die gleiche Stadt enthielt ...
Aber wie dem auch sei, schön das es funktioniert!

Bis zum nächsten mal ...
 
ich suche generell nach der PLZ. Diese ist zu 99% Uniq (ich habe jetzt die Tabelle mit PLZ und Ortsnamen, wo viele Kleinere orte zusammen zu eine PLZ gehören. Natürlich ist das blöd aber naja ich lasse es vorerst so)
 
Code:
string sCommand = string.Concat(
  "BEGIN\r\n",
    "DECLARE @STADT_ID INT\r\n",
    "if not exists(select * from [staedte] where [staedte].[stadt_name]=@City)\r\n",
    "BEGIN\r\n",
      "INSERT INTO [staedte] VALUES(@City)\r\n",
      "SET @STADT_ID=SCOPE_IDENTITY()\r\n
    "END ELSE BEGIN\r\n",
      "SELECT @STADT_ID=STADT_ID FROM STAEDTE WHERE STADT_NAME=@City\r\n",
    "END\r\n",
    "if not exists(select * from [adresse] where [adresse].[plz_id]=@Zip)\r\n",
    "BEGIN\r\n",
      "INSERT INTO [adresse] ([plz_id],[stadtteil],[bundesland],[stadt_id]) " ,
      "VALUES(@Zip,NULL,NULL,@STADT_ID)\r\n",
    "END\r\n", 
    "if not exists(select * from [strassen] where [strassen].[strasse]=@Street AND [strassen].[plz_id]=@Zip)\r\n",
    "BEGIN\r\n",
      "INSERT INTO [strassen] VALUES(@Zip,@Street)\r\n",
    "END\r\n",
  "END");

Ich gehe mal davon aus, das du in STAEDTE eine Identitätsspalte namens STADT_ID (INT) hast. Dann kannst du auch SCOPE_IDENTITY() verwenden um den letzten Wert vom INSERT zu erhalten, andererseits musst du halt mal ein SELECT "bemühen" (siehe ELSE Zweig). Bei SCOPE_IDENTITY() bleibt noch zu erwähnen, das das ganze nur funktioniert, wenn du es unmittelbar nach dem Insert abfragst, denn es liefert für den Gültigkeitsbereich immer die letzte ID unabhängig von der Tabelle. Will sagen ... nach 2 Inserts in unterschiedliche Tabellen wird die neue ID der letzten Tabelle mit ID Spalte zurückgegeben.
 
Zuletzt bearbeitet:
Zurück
Oben