2010-03-02 10 views
6

Ich habe Code ähnlich dem folgenden in einer gespeicherten Prozedur, die eine Zeile in eine Tabelle einfügt, möchte ich die letzte Spalte (FieldD) zu @prmSomeValue festlegen, es sei denn es ist Null, andernfalls verwenden Sie einfach den Standardwert definiert für diese Spalte.Gibt es eine Möglichkeit, Standardspaltenwerte in einer INSERT..SELECT-Anweisung bedingt zu verwenden?

IF (@prmSomeValue IS NULL) 
    INSERT INTO MyTable (fieldA,FieldB,FieldC) 
     SELECT A,B,C 
     FROM MyOtherTable 
ELSE 
    INSERT INTO MyTable (fieldA,FieldB,FieldC,FieldD) 
     SELECT A,B,C,@prmSomeValue 
     FROM MyOtherTable 

Dies funktioniert, aber verletzt das DRY-Prinzip. Ich versuche, einen Weg zu finden, dies mit einer einzigen Insert-Anweisung zu tun. Etwas in der Art des folgenden Pseudocodes.

INSERT INTO MyTable (fieldA,FieldB,FieldC,FieldD) 
     SELECT A,B,C,ISNULL(@prmSomeValue,DEFAULT) 
     FROM MyOtherTable 

Wer hat irgendwelche Ideen?

Update - Eine weitere Wendung
Die Standardeinschränkung ist keine wörtliche Wert, sondern eine Funktion, wie unten gezeigt.

...DEFAULT (suser_sname()) FOR [FieldD] 

aktualisieren
ich das kleinere Übel schließlich punted und wählte und nur den Standardwert Funktion in meine Abfrage anstatt zu fallen bis zum für die Spalte konfigurierten Standard kopiert. Ich mag es nicht, aber es macht den Job mit weniger Wiederholungen in meiner Frage erledigt.

INSERT INTO MyTable (fieldA,FieldB,FieldC,FieldD) 
     SELECT A,B,C,ISNULL(@prmSomeValue,suser_sname()) 
     FROM MyOtherTable 

Antwort

3

Da im Wesentlichen ist es das, was SQL Server tut, Sie so etwas zu vermeiden, zumindest zwei nahezu identische Aussagen (Pseudo-Code) tun könnte:

Ich glaube nicht, dass es einen Weg zu COALESCE mit dem Standardwert gibt.

+0

Interessante Idee. Ich bin mir nicht sicher, ob es besser ist, aber auf jeden Fall eine Bewertung wert. – JohnFx

+0

Dank JohnFx, ich denke, es könnte vorzuziehen sein, wenn es mehr als eine optionale Spalte gibt, die auf diese Weise behandelt werden soll. Dann können Sie sagen "WENN @foo IST NICHT NULL ODER @ bar IST NICHT NULL, UPDATE SET foo = COALESCE (@ foo, foo), bar = COALESCE (@ bar, bar) WHERE" etc., anstatt eine insert-Anweisung zu schreiben für jede mögliche Kombination. –

+0

Verwenden Sie ISNULL anstelle von COALESCE, COALESCE ist für mehrere Argumente vorgesehen. Ich würde nicht für Feld = Parameter/Feld Ansätze gehen, es tötet SQL-Performance, macht es schwieriger, Abfragen und die Verwendung von Indizes zu optimieren. Eine einfache if-Anweisung wäre weitaus effizienter. – Zyphrax

0

Diese Macht Arbeit, hängt davon ab, wenn Sie den Standardwert in einer Standardeinschränkung definiert bedeuten, oder in Code? Wenn "constraint" es scheitert, wenn "code" es funktioniert. Edit: Sie meinen Einschränkung. Dah!

Je nachdem, wie Sie es tun möchten, erfordert die Angabe einer Spalte in der INSERT-Klausel einen Wert.

So Ihre erste Lösung ist, was Sie zu tun haben ...

+0

Ich meinte die Standardeinschränkung für die Spalte definiert. Wie die erste Hälfte meiner IF-Anweisung tun würde. Das wird also nicht funktionieren. Hinweis: Es ist nicht unbedingt erforderlich, die Spalte in der INSERT-Klausel anzugeben. Ich kann mich auf die Spaltenreihenfolge verlassen, wenn es notwendig ist, dies zu tun, obwohl ich es vorziehe. – JohnFx

+0

JohnFx, wenn Sie die Spaltenliste weglassen, müssen Sie die nachfolgende Auswahl die gleiche Anzahl von Spalten haben, die der Tabelle entsprechen, andernfalls erhalten Sie: "Nachricht 213, Ebene 16, Status 1, Zeile 1 Der Spaltenname oder die Anzahl der angegebenen Werte stimmt nicht mit der Tabellendefinition überein. " Selbst wenn das funktionieren würde, wäre ich sehr vorsichtig, wenn es darum geht, sich auf die Spaltenreihenfolge zu verlassen (Ihr Instinkt ist richtig, IMHO). –

2

Ich würde sagen, Ihre Methode ist in Ordnung. Eine einfache Überprüfung gefolgt von einer Einfügung. Wenn Sie sich Sorgen um DRY machen, kapseln Sie den Anruf so, dass er wiederholt aufgerufen wird.

Ich würde sagen, dass Einfügungen/Updates auf einer Datenbank auf einigen Tabellen teuer sein können (hängt vom Entwurfsziel ab), also wenn Sie zusätzlichen Code schreiben müssen, um dieses Szenario zu behandeln, sehe ich kein Problem mit dem Kompromiss.

+0

+1, es ist gut zu versuchen, doppelte Codeblöcke zu verhindern. Viele Programmierer versuchen jedoch, ihre OO-Prinzipien und Programmierpraktiken auf T-SQL anzuwenden. Oft ergeben sich schöne aber ineffiziente Abfragen. Manchmal ist es für die Leistung großartig, 5 ziemlich ähnliche Abfragen anstelle von 1 halbdynamischen zu schreiben - Behalten Sie Ihren Code bei, wie er ist, er ist zentralisiert innerhalb einer gespeicherten Prozedur, leicht zu warten. – Zyphrax

+0

Weißt du nicht, dass sie das Zeug in unseren Köpfen bis zu dem Punkt schlagen, wo es physisch schmerzt, praktisch denselben Code zu haben, der an jedem Ende eines Konditionals dupliziert wird? =) Du könntest aber recht haben, vielleicht denke ich darüber nach. – JohnFx

+1

Wenn Sie nur A oder B haben, stimme ich zu, dass es in Ordnung sein könnte. Aber was passiert, wenn Sie vier solcher Säulen haben? Die Anzahl der möglichen INSERT-Anweisungen, die basierend auf den NULL-Parametern benötigt werden, explodiert sehr schnell. Manchmal müssen Sie Effizienz und Wartung ausbalancieren. –

0

So etwas wie dies funktionieren könnte (tho nicht sehr hübsch):

INSERT INTO MyTable (fieldA,FieldB,FieldC,FieldD) 
SELECT A,B,C, 
    case when @prmSomeValue is null 
then 
     (SELECT text FROM syscomments WHERE id IN (SELECT cdefault FROM syscolumns 
      WHERE id = object_id('MyTable') AND cdefault > 0)) 
    else @prmSomeValue 
    end 
FROM MyOtherTable 
+2

Was passiert, wenn der Standardwert tatsächlich eine Formel (wie GETDATE() oder NEWID()) ist? Es wird als String interpretiert, der je nach Datentyp der Spalte entweder zu einem Fehler oder zu falschen Daten führt. Wollen Sie auch nicht sicherstellen, dass Sie die richtige Spalte erhalten (es könnte mehr als eine Spalte geben, in der cdefault> 0 ist, was zu Msg 512 führt - Unterabfrage gab mehr als einen Wert zurück)? Verwenden Sie für SQL Server 2008 keine Katalogsichten anstelle veralteter Systemtabellen? –

+0

Ich habe über einen ähnlichen Ansatz nachgedacht, war aber ein wenig besorgt über Nebenwirkungen oder Berechtigungsprobleme, die mit der Verwendung von Systemtabellen wie diesem verbunden sind, aber ich nehme an, es fühlt sich solide genug an. Irgendwelche Vorbehalte, um auf dieser Technik anzubieten? – JohnFx

+0

Doh! Ein Hauptproblem bei diesem Ansatz. Wenn der Standardwert eine Funktion ist, wird nur der Name der Funktion eingefügt, in meinem Fall "getdate()". Trotzdem netter Versuch. – JohnFx

Verwandte Themen