MSSQL - Skalarvariable muss deklariert sein

  • VB.NET

Es gibt 23 Antworten in diesem Thema. Der letzte Beitrag () ist von Haudruferzappeltnoch.

    MSSQL - Skalarvariable muss deklariert sein

    Hallo,

    ich habe aktuell das Problem, dass ich Daten in eine vorhandene DB eintragen möchte und immer wieder die untenstehende Fehlermeldung erhalte.

    System.Data.Odbc.OdbcException (0x80131937): ERROR [42000][Microsoft][ODBC SQL Server Driver][SQL Server]Die @B-Skalarvariable muss deklariert werden.

    Die DB ist schon fertig vorgegeben. Ich wollte erstmal nur feste Werte in die DB schreiben, um zu schauen, ob es funktioniert. Ich habe die Variable @B schon auf unterschiedliche Weisen befüllen wollen, daher unten auch noch ein ausgeklammerter Stand, aber ich hatte keinen Erfolg.

    Kann mir jemand einen Tipp geben, was ich falsch mache?

    VB.NET-Quellcode

    1. With cmd
    2. .CommandText = "INSERT INTO dbo.stoerung (MaschID, melder, erf_datum, uhrzeit, memo, art_stoerung, prioritaet, termin1, status, bearbeiter, erl_term, memo1, derz_Standort, masch_status, pos, Ausfallzeit, ausfall_von, ausfall_am, klassifizierung, Art_stoerung_gemeldet, Art_stoerung_abfrage, Aufwand, Taetigkeit, Std_satz, Zeitstempel, Art_verfuegbarkeit_gemeldet, Stoerungsart, Stoerbeseitigung, BearbSi, BearbSiZeit, kor_prioritaet, prio_gemeldet, X, Erst_Am, Erst_Von, Aend_Am, Aend_Von, Praeventiv, AusfADat, AusfAZeit, AusfEDat, AusfEZeit, Bildlink, Betriebsstunden, Vorfall, Link, lieferant, std_zaehler) VALUES (@B, @C, @D, @E, @F, @G, @H, @I, @J, @K, @L, @M, @N, @O, @P, @Q, @R, @S, @T, @U, @V, @W, @X, @Y, @Z, @AA, @AB, @AC, @AD, @AE, @AF, @AG, @AH, @AI, @AJ, @AK, @AL, @AM, @AN, @AO, @AP, @AQ, @AR, @AS, @AT, @AU, @AV, @AW);"
    3. .Parameters.Clear()
    4. '.Parameters.AddWithValue("@B", SqlDbType.Int).Value = CInt(149) 'MaschID
    5. .Parameters.AddWithValue("@B", "149") 'MaschID
    6. .Parameters.AddWithValue("@C", "Bediener") 'melder
    7. .Parameters.AddWithValue("@D", "") 'erf_datum
    8. .Parameters.AddWithValue("@E", "") 'uhrzeit
    9. .Parameters.AddWithValue("@F", "Dies ist ein Test, um zu sehen, ob alles geht.") 'memo
    10. .Parameters.AddWithValue("@G", "2") 'art_stoerung
    11. .Parameters.AddWithValue("@H", "2") 'prioritaet
    12. .Parameters.AddWithValue("@I", "02.02.2024 00:00:00") 'termin1
    13. .Parameters.AddWithValue("@J", "3") 'status
    14. .Parameters.AddWithValue("@K", "Nachname, Vorname") 'bearbeiter
    15. .Parameters.AddWithValue("@L", "02.02.2024 00:00:00") 'erl_term
    16. .Parameters.AddWithValue("@M", "Dies ist ein Test.") 'memo1
    17. .Parameters.AddWithValue("@N", "") 'derz_Standort
    18. .Parameters.AddWithValue("@O", "1") 'masch_status
    19. .Parameters.AddWithValue("@P", "") 'pos
    20. .Parameters.AddWithValue("@Q", "1") 'Ausfallzeit
    21. .Parameters.AddWithValue("@R", "Nachname, Vorname") 'ausfall_von
    22. .Parameters.AddWithValue("@S", "02.02.2024 00:00:00") 'ausfall_am
    23. .Parameters.AddWithValue("@T", "Allgemein") 'klassifizierung
    24. .Parameters.AddWithValue("@U", "2") 'Art_stoerung_gemeldet
    25. .Parameters.AddWithValue("@V", "1") 'Art_stoerung_abfrage
    26. .Parameters.AddWithValue("@W", "1") 'Aufwand
    27. .Parameters.AddWithValue("@X", "Instandsetzung/ Mech.") 'Taetigkeit
    28. .Parameters.AddWithValue("@Y", "45,12") 'Std_satz
    29. .Parameters.AddWithValue("@Z", "07.02.2024 06:51:25") 'Zeitstempel
    30. .Parameters.AddWithValue("@AA", "0") 'Art_verfuegbarkeit_gemeldet
    31. .Parameters.AddWithValue("@AB", "Allgemein") 'Stoerungsart
    32. .Parameters.AddWithValue("@AC", "Fehlersuche") 'Stoerbeseitigung
    33. .Parameters.AddWithValue("@AD", "Nachname, Vorname") 'BearbSi
    34. .Parameters.AddWithValue("@AE", "07.02.2024 15:27:21") 'BearbSiZeit
    35. .Parameters.AddWithValue("@AF", "") 'kor_prioritaet
    36. .Parameters.AddWithValue("@AG", "") 'prio_gemeldet
    37. .Parameters.AddWithValue("@AH", "") 'X
    38. .Parameters.AddWithValue("@AI", "") 'Erst_Am
    39. .Parameters.AddWithValue("@AJ", "") 'Erst_Von
    40. .Parameters.AddWithValue("@AK", "") 'Aend_Am
    41. .Parameters.AddWithValue("@AL", "") 'Aend_Von
    42. .Parameters.AddWithValue("@AM", "") 'Praeventiv
    43. .Parameters.AddWithValue("@AN", "02.02.2024 00:00:00") 'AusfADat - nur Datum
    44. .Parameters.AddWithValue("@AO", "00.01.1900 19:30:00") 'AusfAZeit - nur Uhrzeit
    45. .Parameters.AddWithValue("@AP", "02.02.2024 00:00:00") 'AusfEDat - nur Datum
    46. .Parameters.AddWithValue("@AQ", "00.01.1900 19:45:00") 'AusfEZeit - nur Uhrzeit
    47. .Parameters.AddWithValue("@AR", "") 'Bildlink
    48. .Parameters.AddWithValue("@AS", "") 'Betriebsstunden
    49. .Parameters.AddWithValue("@AT", "Test") 'Vorfall
    50. .Parameters.AddWithValue("@AU", "") 'Link
    51. .Parameters.AddWithValue("@AV", "") 'lieferant
    52. .Parameters.AddWithValue("@AW", "") 'std_zaehler
    53. End With
    Den DbCommandBuilder kannte ich ehrlich gesagt nicht, schaue ich mir aber nachher gleich an.
    Ich programmiere nicht professionell, nur für Eigenbedarf, aber wenn wie gesagt, ich sehe es mir an.

    Der Primärschlüssel liegt auf der ID (mit Autoincrement), diese ist im Kommando oben nicht enthalten, da sie ja automatisch erstellt wird.
    Sorry, aber die Fehlermeldung ist so eindeutig und einfach bei MS zi finden.

    Du versuchst mit deinen ganzen @xyz eine Variable anzulegen, welche du vor her nicht Deklarierst.

    Und alles nur weil du vollkommen falsch einem INSERT versuchst.
    Egal ob nun zu Fuß, per CommandBuilder, oder wie man es seit Jahren richtig macht mit einem Object Relationship Mapper (z. B. Entity Framework), dann würde es auch funktionieren.

    Versuche mal dein Insert im Management Studio direkt als T-SQL nachzubauen.
    Die deutsche Sprache ist Freeware, du kannst sie benutzen, ohne dafür zu bezahlen. Sie ist aber nicht Open Source, also darfst du sie nicht verändern, wie es dir gerade passt.
    Als Nachtrag zu MrTrebron:

    Murdersquad schrieb:

    .Parameters.AddWithValue("@B", "149") 'MaschID


    Ist MaschID in der Datenbank eine Zahl- oder ein Text-Spalte? Es wird mit dem Aufruf ein Text übergeben.
    NB. Es ist doch schön, wenn man lesbare Namen vergibt. Siehe auch [VB.NET] Beispiele für guten und schlechten Code (Stil).

    MrTrebron schrieb:

    wie man es seit Jahren richtig macht mit einem Object Relationship Mapper (z. B. Entity Framework)
    Man kann es auch anders richtig machen. EF macht viele Sachen, die ich gar nicht haben will.

    MrTrebron schrieb:

    Versuche mal dein Insert im Management Studio direkt als T-SQL nachzubauen
    Das geht nicht, was du meinst ist wohl Declare @B... aber wenn man Parameter übergibt mit VB, dann wird daraus nicht erst ein Skript geschrieben. Die fließen einfach mit ein, wie weiß ich aber auch nicht.
    Mit SqlCommand funktioniert es auch genauso wie der TE macht.

    Das muss was mit OdbcCommand zu tun haben. Der Commandbuilder sollte funktionieren, aber wäre trotzdem gut zu wissen, was da das Problem ist mit den Parametern
    Ich habe mal irgendwo diesen Code gefunden, mit dem ich mir den Text ausgegeben kann, der an die Datenbank weitergereicht wird.

    VB.NET-Quellcode

    1. ' Function to get the text send to Database from OleDbCommand with parameters
    2. ' use: Debug.Print(GetFullCommandSQL(comm))
    3. Public Function GetFullCommandSQL(cmd As OleDbCommand) As String
    4. Dim sql As String = cmd.CommandText
    5. For Each p As Data.Common.DbParameter In cmd.Parameters
    6. If sql.Contains(p.ParameterName) AndAlso p.Value IsNot Nothing Then
    7. If p.Value.GetType Is GetType(String) Then
    8. sql = sql.Replace(p.ParameterName,
    9. String.Format("'{0}'", p.Value.ToString))
    10. Else
    11. sql = sql.Replace(p.ParameterName, p.Value.ToString)
    12. End If
    13. End If
    14. Next
    15. Return sql
    16. End Function
    NB. Es ist doch schön, wenn man lesbare Namen vergibt. Siehe auch [VB.NET] Beispiele für guten und schlechten Code (Stil).
    @B und Co sind Variablen, welche vor der Verwendung deklariert werden müssen. Das geschieht nicht.
    Siehe auch: learn.microsoft.com/de-de/sql/…ror?view=sql-server-ver16

    Es wurde ein Insert Query aus einem anderen Zusammenhang gerissen und dies nur nun versucht zu verwenden.

    Auch wenn es nicht mein Stil wäre, aber hier klick würde man fündig werden. Dann muss man nur noch Inserts verstehen.

    @Haudruferzappeltnoch du möchtest also nicht Objektorientiert arbeiten und dich im Code nicht um das Backend kümmern müssen? Okay. Aber jetzt sage nicht DataSet
    Die deutsche Sprache ist Freeware, du kannst sie benutzen, ohne dafür zu bezahlen. Sie ist aber nicht Open Source, also darfst du sie nicht verändern, wie es dir gerade passt.
    Probiers halt selbst aus, wenn du es nicht glauben willst...
    Hier nix selbst tippeln bzw. den ConnectionString musst selbst wohl reintun:
    Spoiler anzeigen
    Machst du Tabelle

    SQL-Abfrage

    1. /****** Object: Table [dbo].[Test] Script Date: 10.02.2024 18:24:08 ******/
    2. SET ANSI_NULLS ON
    3. GO
    4. SET QUOTED_IDENTIFIER ON
    5. GO
    6. CREATE TABLE [dbo].[Test](
    7. [ID] [bigint] NOT NULL,
    8. PRIMARY KEY CLUSTERED
    9. (
    10. [ID] ASC
    11. )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
    12. ) ON [PRIMARY]
    13. GO
    Machst Du Insert

    VB.NET-Quellcode

    1. Dim cmd = New SqlCommand("Insert Into Test Values (@B)", New SqlConnection(DBZugriff.ConnectionString(DataBase.DeineDataBase)))
    2. cmd.Parameters.AddWithValue("@B", 1)
    3. cmd.Connection.Open()
    4. cmd.ExecuteNonQuery()
    5. cmd.Connection.Close()

    Der erste Artikel behandelt T-SQL, da ist das ein anderes Thema
    Zu TableAdapters kann ich nix sagen, ich bin da sogar noch bei den DataAdaptern, Fill und Update Befehl reichen mir vollkommen.
    Obwohl ich objektorientiert arbeite und mir das auch gefällt heißt das noch lange nicht, das ich nicht auch andere Codingstile für sinnvoll und auch "richtig" erachte.

    Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von „Haudruferzappeltnoch“ ()

    Dein Beispiel hat nicht so viel mit dem eigentlichen Insert zu tun.
    Verkürzt wäre es:

    SQL-Abfrage

    1. ​INSERT INTO [dbo].[DbName] (column1, coloumn2, column3) VALUES (@B, @C, @D)


    Wäre möglich, dass es Methoden im .net gibt, welche die Deklaration im Hintergrund selbst erledigen.

    Und wenn ich gegen eine MS-SQL Arbeite, sollte am Ende immer gültiges T-SQL raus fallen.
    Die deutsche Sprache ist Freeware, du kannst sie benutzen, ohne dafür zu bezahlen. Sie ist aber nicht Open Source, also darfst du sie nicht verändern, wie es dir gerade passt.
    Es geht nicht um die Kürze, sondern in deinem Insert gibst du keine Column Names an, und nur einen Value.
    Mein Beispiel ist ein verkürzten Beispiel des TE

    Also gibt es Methoden, die es erlauben unsaubere Queries zu schreiben und diese zu fixen?
    Die deutsche Sprache ist Freeware, du kannst sie benutzen, ohne dafür zu bezahlen. Sie ist aber nicht Open Source, also darfst du sie nicht verändern, wie es dir gerade passt.
    Als Datenbankbaumeister wirst du wohl wissen dass Columnnames nur angegeben werden müssen, wenn nicht alle Spalten mit Werten versorgt werden beim Insert. (Und das hat nix mit .NET zutun, das ist T-SQL)
    Ich hab dir extra einen Create dazu getan damit du die richtige Tabelle zur Hand hast.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Haudruferzappeltnoch“ ()

    Wer nicht Angibt was er haben oder ändern will, schreib unsauber. Consume what you need. Change only what is nevessary.

    Und wie ich schon schrieb, schön für dich, dass deine .net Methode dir arbeit abnimmt. Die Deklaration einfach im Hintergrund erledigt.
    Am Ende des Tages musst du eben immer den SQL-Dialekt erzeugen.

    Wenn also der TE seinen Insert auf dein Beispiel umbaut, sollte es ja nun für ihn reichen.
    Die deutsche Sprache ist Freeware, du kannst sie benutzen, ohne dafür zu bezahlen. Sie ist aber nicht Open Source, also darfst du sie nicht verändern, wie es dir gerade passt.
    Ich habe es nochmal getestet. Wenn ich meinen Befehl bei MySQL verwende, dann wird alles in die DB gehauen, ohne Probleme.
    Wenn ich es über ODBC mache, dann kommt die Meldung, dass die Variable nicht deklariert sei. Ich habe im MSDN gelesen, dass ich das DECLARE bräuchte, aber da ich es im MySQL nicht verwende, dachte ich, dass etwas anderes falsch wäre.

    Ich muss ganz ehrlich sagen, dass ich mir den DBCommandBuilder in der MSDN und bei dotnetperls zwar angesehen habe, aber die Beispiele sind einfach blöd... gibt es da irgendwo etwas schönes?

    Bei dem obenstehenden Link zur MSDN (learn.microsoft.com/en-us/visu…base?view=vs-2022&tabs=vb) sehe ich gar keinen Unterschied zu meinem Vorgehen.
    Jetzt bin ich ein wenig verwirrt.
    Du schreibst im Titel MSSQL
    Jetzt schreibst du MySQL?
    Was benutzt du denn jetzt?

    Sind ja zwei unterschiedliche Dialekte.

    Mit direkt eingeben wäre bei MSSQL das SQL Server Management Studio?
    Die deutsche Sprache ist Freeware, du kannst sie benutzen, ohne dafür zu bezahlen. Sie ist aber nicht Open Source, also darfst du sie nicht verändern, wie es dir gerade passt.
    Also das Projekt, worum es hier geht nutzt MSSQL und ODBC. Hier ist die DB bereits fertig vorgegeben und die Daten werden über verschiedene Programme eingegeben.
    Ich habe aber auch meinen MySQL-Server, den ich immer zum Testen nehme, da ich eher auf MySQL gepolt bin. Hier habe ich in der MySQL-Workbench und auch über VB.NET die Daten problemlos eingegeben.
    Maja, du kannst aber den Insert in deinen MySQL Server nicht mit dem Insert in den verwendeten MSSQL Server gleich setzten.
    Es handelt sich zm zwei verschiedene Systeme (da würde ich bei größeren Versionsunterschieden zwischen zwei MSSQL Servern sogar vorsichtig sein) und zwei Unterschiedliche SQL-Dialekte.
    Da kann man nicht von A auf B schließen.

    Funktioniert dein Insert im MS SQL Server Management Studio gegen die Original DB, bzw. eine Kopie als Entwicklungsumgebung?
    Die deutsche Sprache ist Freeware, du kannst sie benutzen, ohne dafür zu bezahlen. Sie ist aber nicht Open Source, also darfst du sie nicht verändern, wie es dir gerade passt.
    Nun denn eine Lösung zu meinem Problem konnte ich jetzt noch nicht herbeiführen...
    Muss ich jetzt wirklich das DECLARE voran nutzen oder verzichte ich lieber auf Parameters.AddWithValue und schreib den Kram direkt in den String oder hat noch jemand einen entscheidenden Tipp, wie es doch so oder besser funktionieren könnte?