Die Frage ist etwas vage in Bezug darauf, wie BCP ausgeführt wird, außer dass es innerhalb einer gespeicherten Prozedur durchgeführt wird. Da aber , dass alles , was wir wirklich im Moment wissen, werde ich davon ausgehen , dass Sie anrufen BCP.EXEaus xp_cmdshell.
Wenn Sie einfach die tatsächlichen Fehler erfassen möchten, die von ausgelöst werden BCP, ist dies sehr einfach, da der ERRORLEVELWert als INTvon der xp_cmdshellgespeicherten Prozedur zurückgegeben wird:
DECLARE @ErrorLevel INT;
EXEC @ErrorLevel = xp_cmdshell
N'BCP "SELECT * FROM sys.objects where 1= " queryout C:\temp\BCPtest.txt -T -w ';
SELECT @ErrorLevel;
Kehrt zurück:
1
Wenn Sie jedoch Abfragen behandeln möchten, die erfolgreich abgeschlossen wurden und dennoch 0 Zeilen als "Fehler" -Zustand zurückgeben, ist dies ebenfalls möglich. Dies erfordert nur etwas mehr Aufwand:
DECLARE @ErrorLevel INT;
EXEC @ErrorLevel = xp_cmdshell
N'BCP "SELECT * FROM sys.objects where 1= 0 " queryout C:\temp\BCPtest.txt -T -w && (FORFILES /P C:\TEMP\ /M BCPtest.txt /C "CMD /C IF @fsize LSS 3 DEL C:\TEMP\BCPtest.txt" & IF NOT EXIST C:\temp\BCPtest.txt EXIT -3)';
SELECT @ErrorLevel;
Kehrt zurück:
-3
Bitte beachten Sie, dass die lange Befehlszeile entweder als einzelne Zeile beibehalten oder in ein .CMDSkript eingefügt werden muss, damit sie ordnungsgemäß funktioniert.
Die zusätzliche Logik in einem besser lesbaren Format lautet:
&& (
FORFILES /P C:\TEMP\
/M BCPtest.txt
/C "CMD /C IF @fsize LSS 3 DEL C:\TEMP\BCPtest.txt"
& IF NOT EXIST C:\temp\BCPtest.txt EXIT -3
)
Erläuterung:
&&Dieser Operator führt den Befehl auf der rechten Seite nur aus, wenn der Befehl auf der linken Seite erfolgreich ausgeführt wurde. Der Grund für die Verwendung dieses Operators besteht darin BCP, den ERRORLEVELWert festlegen zu können, wenn ein Fehler auftritt. die Befehle auf der rechten Seite werden nur benötigt , wenn BCPsie nicht in einen Fehler läuft noch zurück 0 Zeilen.
(Die Klammern gruppieren die darin enthaltenen Befehle. Dadurch können wir die Befehle FORFILESund IFnur ausführen, wenn BCPsie erfolgreich abgeschlossen wurden. Andernfalls wird keiner der Befehle innerhalb von (und )ausgeführt.
FORFILESDurchläuft eine Liste von Dateien, die von bestimmten Schaltern angegeben werden, und führt für jede Datei einen Befehl aus, der den Kriterien entspricht (ähnlich dem findBefehl in Unix).
/Pist der Startpfad. Es muss ein Pfad sein und darf den Dateinamen nicht enthalten.
/M ist der Dateinamenfilter oder "Maske".
/Cist der Befehl, der für jede Datei ausgeführt werden soll. Es muss so ziemlich anfangen CMD /C. Der IFBefehl testet die Größe der Datei, die über die @fsizeVariable gefunden wird, die durch ersetzt wird. FORFILESWenn sie kleiner als 3 ist (dh LSS 3), wird die Datei einfach gelöscht. Bei meinen Tests stellte ich fest, dass die Verwendung von entweder -coder nichts mit BCPzur Angabe der ASCII / VARCHAR-Ausgabe zu einer leeren Datei mit 0 Byte führen würde. Die Verwendung der -wUnicode / NVARCAR-Ausgabe führt jedoch zu leeren Dateien mit 2 Bytes (dies sollte das Byte Order Mark sein). Daher deckt das Testen auf "Größe <3" beide Szenarien ab.
Der Grund für das Löschen der Datei ist, dass sie im übergeordneten Prozess getestet werden kann. Da CMD /Cder Befehl zum Ausführen des Befehls für Dateien verwendet wird, die von gefunden werden FORFILES, handelt es sich um einen Unterprozess, und Umgebungsvariablen bleiben nicht bestehen (ähnlich wie beim Erstellen einer lokalen temporären Tabelle in Dynamic SQL), und das Beenden mit einem Fehlercode wird einfach an das übergeordnete Element zurückgegeben Prozess wie es schon gehen würde. Das Erstellen einer leeren Datei als Indikator ist eine Option, muss dann aber entweder bereinigt werden oder ist unübersichtlich. Und wenn der Prozess als Fehler angesehen wird, weil keine Zeilen zurückgegeben werden, möchten wir die Datei sowieso nicht.
& Dieser Operator führt den Befehl auf der rechten Seite aus, unabhängig vom Erfolgs- oder Fehlerstatus des Befehls auf der linken Seite.
IF Dies führt einen einfachen Test auf das Vorhandensein der angegebenen Datei durch. Wenn diese Datei nicht vorhanden ist, wird der angegebene Befehl ausgeführt.
EXIT -3Dadurch wird der aktuelle Prozess (der Betriebssystemprozess der obersten Ebene, von dem gestartet wurde xp_cmdshell) beendet, während der ERRORLEVELWert auf gesetzt wird -3. Sie können den -3Wert in einen beliebigen Wert ändern. Achten Sie jedoch darauf, keine Werte zu verwenden, die bereits von verwendet werden, BCPdamit Sie zwischen diesen unterscheiden können. Das muss EXITnur explizit verwendet werden, wenn Sie festlegen möchten ERRORLEVEL(ähnlich wie entweder keine Angabe RETURNam Ende einer gespeicherten Prozedur oder Angabe, um einen Nichtwert zurückzugeben 0).