SQL MS SQL Fetcht falsch? (MS SQL 2005)

roker002

Commander
Registriert
Dez. 2007
Beiträge
2.061
Ich habe ein kleines Problem! ich versuche von eine DB in die andere die Tabelleninhalte zu übertragen!

Ich dachte man kann im C# mit managed Code das machen aber wenn ich im SQL Server das selbst mache geht es viel schneller!

Naja auf jeden fall mein Problem ist:

Ich fetche eine Tabelle mit Cursor. Ja da macht der SQL server kein problem.
Code:
DECLARE monate CURSOR FOR
(SELECT * FROM [dbo].[vorlage_monat] WHERE vorlage = (SELECT id FROM .[dbo].[vorlagen] where p = 17) AND pn != 0)

Das ist eine echtabfrage mit Echtdaten. Die Innere abfrage mit dem Select id liefert einen eideutigen ergebnis egela welcher p das jetzt ist, da p in der gesamte aufstellung der tabelle immer nur 1x vorkommt.
OK es geht weiter!

Code:
OPEN monate

-- Perform the first fetch.
FETCH NEXT FROM monate


-- Check @@FETCH_STATUS to see if there are any more rows to fetch.
WHILE @@FETCH_STATUS = 0
BEGIN
   -- This is executed as long as the previous fetch succeeds.
	FETCH NEXT FROM monate
	INTO @monatid, @vorlage, @pn, @lp

	SET @preis = 
	(SELECT ... aus @pn);
	
	select @preis AS Preis, @monatid AS Monat, @vorlage AS R, @pn AS PN, @lp AS LP
	
	INSERT INTO ...
END

CLOSE monate
DEALLOCATE monate

ROLLBACK TRANSACTION

ROLLBACK TRANS habe ich gemacht damit die daten nicht in Tabelle geschrieben werden, da ich diese nur zu testzwecken benutze und später ehe per hand löschen muss weil es immer noch einen Fehler gibt!

jetzt das Problem! ich Fetche die Daten aus der Abfrage oben in die Lokale Variablen. Die sind oben erstellt und sind alle vorhanden.
Damit ich sehe welche Daten jetzt durchgefetcht werden habe ich kleinen Select eingebaut. Beim Preis habe ich immer die richtige Werte. Jetzt gehts los!
Bei monatsid überspringt er den ersten Werte und liefert direkt den zweiten! Ich habe insgesamt bei der Abfrage 4 Elemente.
Also erscheint bei mir die Reihenfolge

Code:
2
3
4
4

Der sollte aber
Code:
1
2
3
4
Fetchen

Woran liegt es?
 
Ich schätze jetzt einfach mal, dein 2.
FETCH NEXT FROM monate
muss ans Ende deiner Schleife!

Tip: Benutze keine Cursor. Selbst Microsoft empfiehlt die - glaube ich - nicht.

Lieber mit Joins arbeiten, das sollte bei deiner Tabelle gehen.

Gruß,
David.
 
mit Joins wird die Abfrage zu riesig!

Man muss beachten... wenn ich die Daten aus dem monate nicht in die Local Variable lade dann habe ich immer in denen 0 stehen!

FETCH NEXT FROM monate
INTO @monatid, @vorlage, @pn, @lp


EDIT:

Nach lange überlegungen wieso es nicht funktioniert habe ich beschloßen alles noch mal zu überprüfen!

Problem bei mir war.... COPY PASTE.
Hab den Code aus der MS Seite rausgefischt! Und sieh da... es steht einmal auskommentiert! Performe First Fetch.. schreibt man das bisschen um

Code:
OPEN monate

-- Perform the first fetch.
FETCH NEXT FROM monate
INTO @monatid, @vorlage, @pn, @lp  -- Schreibe Hier die [COLOR="Red"]ERSTEN[/COLOR] Daten rein bevor die schleife anfängt!

-- Check @@FETCH_STATUS to see if there are any more rows to fetch.
WHILE @@FETCH_STATUS = 0
BEGIN
   -- This is executed as long as the previous fetch succeeds.
	
	SET @preis =(...);
	
	select @preis AS Preis, @monatid AS Monat, @vorlage AS R, @pn AS PN, @lp AS LP
	
	INSERT INTO ....
END

CLOSE monate
DEALLOCATE monate

ROLLBACK TRANSACTION


Naja muss man halt aufpassen was man da vom Internet her kopiert!
 
Zuletzt bearbeitet:
Hallo Roker,
auch wenn MS in seinen Tutorials so etwas reinschreibt ist es nicht wirklich gut, denn es ist von der Wartung her beschissen 2 FETCHES zu pflegen (vor und in der Schleife). Ich bin eher dazu übergegangen, in einer TSQL Prozedur das Ganze wie folgt aufzuziehen:

Code:
OPEN monate
WHILE 1=1 BEGIN
  FETCH NEXT FROM monate INTO @monatid, @vorlage, @pn, @lp
  IF NOT @@FETCH_STATUS = 0 BREAK

  -- do what you want here
  -- ...

END
CLOSE monate
DEALLOCATE monate

Das hätte den Vorteil das nur an einer Stelle der FETCH angepasst weren müsste, der Effekt ist aber der Gleiche. Sonst hast du den FETCH vor der Schleife und am Ende der Schleife, was bei großen Schleifen schnell zu Fehlern führen kann, wenn man mal das 2. Fetch vergisst. Ebenso kann es sein, dass man das 2. Fetch am Anfang der Schleife macht, was dann dazu führt, das der 1.Fetch keine Relevanz mehr hat. Also alles in allem ist es nicht gut die Fetches so zu splitten. Besser nur einen verwenden und glücklich sein...

PS: Wenn du einen LOCAL Cursor verwendest, dann könntest du dir den Kram mit deallocate und close sparen, da der Cursor nur so lange lebt wie die Prozedur. Ebenso wäre das FAST_FORWARD eine optimierte Variante eines Cursors, wo es nur in einer Richtung fetcht und schneller ausgeführt wird als ein normaler Cursor.
 
Zuletzt bearbeitet: (Rokers Bugfix für Fetch Status übernommen)
hmm ich muss eigentlich mehrere Fetches reinschreiben! gibt es da schwierigkeiten?

Aber so wie ich es bei dir sehen, sieht es viel besser aus als bei MS!


EDIT

Muss es nicht

IF @@FETCH_STATUS != 0 BREAK
Sein?
 
Zuletzt bearbeitet:
Mehrere Fetches in einer Prozedur sind kein Problem. Du kannst ja aus mehreren Cursorn fetchen ohne das diese sich gegenseitig beeinflußen. Aber mehrere Fetches auf den selben Cursor gemacht, kann ich nur abraten, weil das den Code schnell in ein großes unbekanntes etwas verwandelt wo nicht mehr die Logik nachvollzogen werden kann bzw. erst mühsam interpretiert werden muss. Das kostet dann Zeit im Support/Wartung und würde aus meiner Sicht unrentabel. Lieber ein(!) Fetch für einen Cursor und gut ist. Da gibts nicht so viele Interpretation. Desweiteren würde ich nicht den Cursor über "SELECT * ..." definieren, sondern immer die Spaltenauflistung angeben. Damit ist es auch sofort klar was gefetcht wird. Das erspart Zeit und Geld in der Pflege. Dachte eigentlich das ein SELECT * nicht funktioniert. Aber naja habs auch noch nie riskiert, da ich gern sehe, was ich eingebe und heraus bekomme. Ebenso ist die Frage, wie gut deine Prozedur arbeitet, wenn die Anordnung der Spalten innerhalb der Tabelle geändert wird. Ich würde mal vermuten, dass du dann in die fiesen kleinen Probleme reinrennst, die schwer zu erkennen sind.

BTW: Immer unmittelbar den Fetch Status nach dem Fetch prüfen, da sonst der Status des 1. Fetches vom 2. Fetch überschrieben wird.
 
Ne select * werde ich rausnehme und durch sinnvollere nachvollziehbare werte ersten. es ist immer noch zum testen! währe ja sinnlose andere werte mitzugeben!

Wegen Cursors. Ja ich dachte auch an mehrere nicht an den einzelnen den ich wieder überschreibe!

Naja wenn es nicht klappen soll schreibe ich nochmal rein!
 
Mit der Prüfung des FETCH STATUS hast du recht, war Fehler von meiner Seite: STRG+C, STRG+V ist tödlich. ;) Sorry. Habs auch gleich mal in meinem Beispiel korrigiert.

Dann viel Erfolg.
Rossibaer
 
Zuletzt bearbeitet: (Rokers Bugfix übernommen)
ne frage! Wie hängt FETCH_STATUS mit einzelnen CURSOREN zusamen? wenn ich jetzt 2 Cursore habe... ich habe leider keine ahnung was genau bei FETCH_STATUS passiert wenn ein cursor gefetched wird!
ooh je es funktioniert! Ohne jeglichen zwischencodes von C# :D Muss halt paar variablen mitübergeben aber sonst keine zusätzliche schleifen!
 
Zuletzt bearbeitet:
FETCH_STATUS enthält die Statusinfo über den letzten gemachten Fetch unabhängig von welchem Cursor der Fetch getätigt wurde. D.h. wenn du 2x fetchst ohne zwischen durch zu prüfen, wirst du nur das Ergebnis des letzten Fetches im Status sehen. Alternativ kannst du dir auch nach jedem Fetch den Wert von FETCH_STATUS in einer Variablen speichern und abschließend nach allen Fetches die Prüfungen machen.
 
Zurück
Oben