it-swarm.com.de

Fügen Sie den Standardwert ein, wenn der Parameter null ist

Ich habe eine Tabelle mit einer Spalte mit einem Standardwert:

create table t (
    value varchar(50) default ('something')
)

Ich verwende eine gespeicherte Prozedur, um Werte in diese Tabelle einzufügen:

create procedure t_insert (
    @value varchar(50) = null
)
as 
insert into t (value) values (@value)

Die Frage ist, wie bekomme ich die Standardeinstellung, wenn @valuenull ist? Ich habe es versucht:

insert into t (value) values ( isnull(@value, default) )

Das hat offensichtlich nicht funktioniert. Auch versuchte eine case-Anweisung, aber das war auch nicht gut. Irgendwelche anderen Vorschläge? Mache ich das falsch?

Update: Ich versuche das zu erreichen ohne muss:

  1. pflegen Sie den default-Wert an mehreren Stellen und
  2. verwenden Sie mehrere insert-Anweisungen.

Wenn das nicht möglich ist, muss ich wohl damit leben. Es scheint nur so, dass etwas erreichbar sein sollte.

Hinweis: Meine aktuelle Tabelle enthält mehr als eine Spalte. Ich schrieb gerade schnell ein Beispiel.

38
chrisofspades

Versuchen Sie eine if-Anweisung ... 

if @value is null 
    insert into t (value) values (default)
else
    insert into t (value) values (@value)
12
Dave DuPlantis

Christophe, 

Der Standardwert für eine Spalte wird nur angewendet, wenn Sie die Spalte in der INSERT-Anweisung nicht angeben.

Da Sie explizit die Spalte in Ihrer Einfügeanweisung auflisten und explizit auf NULL setzen, wird der Standardwert für diese Spalte überschrieben

Was Sie tun müssen, ist "wenn eine Null in Ihr Sproc übergeben wird, dann versuchen Sie nicht, für diese Spalte einzufügen".

Dies ist ein schnelles und unangenehmes Beispiel dafür, wie Sie dies mit etwas dynamischem SQL tun.

Erstellen Sie eine Tabelle mit einigen Spalten mit Standardwerten ...

CREATE TABLE myTable (
    always VARCHAR(50),
    value1 VARCHAR(50) DEFAULT ('defaultcol1'),
    value2 VARCHAR(50) DEFAULT ('defaultcol2'),
    value3 VARCHAR(50) DEFAULT ('defaultcol3')
)

Erstellen Sie einen SPROC, der Ihre Einfügeanweisung basierend auf Eingabeparametern dynamisch erstellt und ausführt

ALTER PROCEDURE t_insert (
    @always VARCHAR(50),
    @value1 VARCHAR(50) = NULL,
    @value2 VARCHAR(50) = NULL,
    @value3 VARCAHR(50) = NULL
)
AS 
BEGIN
DECLARE @insertpart VARCHAR(500)
DECLARE @valuepart VARCHAR(500)

SET @insertpart = 'INSERT INTO myTable ('
SET @valuepart = 'VALUES ('

    IF @value1 IS NOT NULL
    BEGIN
        SET @insertpart = @insertpart + 'value1,'
        SET @valuepart = @valuepart + '''' + @value1 + ''', '
    END

    IF @value2 IS NOT NULL
    BEGIN
        SET @insertpart = @insertpart + 'value2,'
        SET @valuepart = @valuepart + '''' + @value2 + ''', '
    END

    IF @value3 IS NOT NULL
    BEGIN
        SET @insertpart = @insertpart + 'value3,'
        SET @valuepart = @valuepart + '''' + @value3 + ''', '
    END

    SET @insertpart = @insertpart + 'always) '
    SET @valuepart = @valuepart + + '''' + @always + ''')'

--print @insertpart + @valuepart
EXEC (@insertpart + @valuepart)
END

Die folgenden 2 Befehle sollten Ihnen ein Beispiel dafür geben, was Sie als Ausgänge möchten ...

EXEC t_insert 'alwaysvalue'
SELECT * FROM  myTable

EXEC t_insert 'alwaysvalue', 'val1'
SELECT * FROM  myTable

EXEC t_insert 'alwaysvalue', 'val1', 'val2', 'val3'
SELECT * FROM  myTable

Ich weiß, dass dies ein sehr komplizierter Weg ist, um das zu tun, was Sie tun müssen. Sie könnten wahrscheinlich auch den Standardwert aus dem InformationSchema für die relevanten Spalten auswählen die Spitze des Verfahrens

9
Eoin Campbell

Soweit ich weiß, wird der Standardwert nur eingefügt, wenn Sie in der Einfügeanweisung keinen Wert angeben. In einer Tabelle mit drei Feldern müssten Sie zum Beispiel Folgendes tun (Wert2 wird als Standardwert verwendet).

INSERT INTO t (value1, value3) VALUES ('value1', 'value3')

Dann wäre value2 voreingestellt. Vielleicht wird jemand sagen, wie man dies für eine Tabelle mit einem einzelnen Feld erreichen kann.

3
Brian Hasden

chrisofspades, 

Soweit ich weiß, dass dieses Verhalten nicht mit der Funktionsweise der DB-Engine kompatibel ist, gibt es eine einfache Lösung (ich weiß nicht, ob elegant, aber performant), um Ihre beiden Ziele zu erreichen: DO NOT

  1. den Standardwert an mehreren Stellen beibehalten, und 
  2. verwenden Sie mehrere Einfügeanweisungen.

Die Lösung besteht darin, zwei Felder zu verwenden, eines für die Einfügung mit Nullwerten und das andere für die Auswahl berechnete Feld:

CREATE TABLE t (
    insValue VARCHAR(50) NULL
    , selValue AS ISNULL(insValue, 'something')
)

DECLARE @d VARCHAR(10)
INSERT INTO t (insValue) VALUES (@d) -- null
SELECT selValue FROM t

Mit dieser Methode können Sie sogar die Verwaltung von Geschäftsvorgaben in einer Parametertabelle zentralisieren, indem Sie eine Ad-hoc-Funktion einrichten, um dies zu tun. 

selValue AS ISNULL(insValue, 'something')

for

selValue AS ISNULL(insValue, **getDef(t,1)**)

Ich hoffe das hilft.

2

Wahrscheinlich nicht die leistungsfähigste Methode, aber Sie könnten eine Skalarfunktion erstellen, die das Informationsschema mit dem Tabellen- und Spaltennamen abruft und diese dann mit der zuvor ausgeführten isnull-Logik aufruft:

    CREATE FUNCTION GetDefaultValue
    (
        @TableName VARCHAR(200),
        @ColumnName VARCHAR(200)
    )
    RETURNS VARCHAR(200)
    AS
    BEGIN
        -- you'd probably want to have different functions for different data types if
        -- you go this route
    RETURN (SELECT TOP 1 REPLACE(REPLACE(REPLACE(COLUMN_DEFAULT, '(', ''), ')', ''), '''', '') 
            FROM information_schema.columns
            WHERE table_name = @TableName AND column_name = @ColumnName)

    END
    GO

Und dann nennen wir es so:

INSERT INTO t (value) VALUES ( ISNULL(@value, SELECT dbo.GetDefaultValue('t', 'value') )
2
Lurker Indeed

Das ist das Beste, was ich finden kann. Es verhindert, dass die SQL-Injection nur eine insert-Anweisung verwendet und mit mehreren case-Anweisungen erweitert werden kann.

CREATE PROCEDURE t_insert (     @value varchar(50) = null )
as
DECLARE @sQuery NVARCHAR (MAX);
SET @sQuery = N'
insert into __t (value) values ( '+
CASE WHEN @value IS NULL THEN ' default ' ELSE ' @value ' END +' );';

EXEC sp_executesql 
@stmt = @sQuery, 
@params = N'@value varchar(50)',
@value = @value;

GO
2
sqlserverguy

Sie können Standardwerte für die Parameter von gespeicherten Prozeduren verwenden:

CREATE PROCEDURE MyTestProcedure ( @MyParam1 INT,
@MyParam2 VARCHAR(20) = ‘ABC’,
@MyParam3 INT = NULL)
AS
BEGIN
    -- Procedure body here

END

Wenn @ MyParam2 nicht angegeben wird, hat es den Wert 'ABC' ...

1
CMS

Geben Sie beim Einfügen nicht die Spalte oder den Wert an. Der fehlende Wert wird durch den Wert der DEFAULT-Konstante ersetzt.

Ich weiß nicht, wie das in einer einzelnen Spaltentabelle funktionieren würde. Ich meine: es würde, aber es wäre nicht sehr nützlich.

0
cfeduke

Das Muster, das ich im Allgemeinen verwende, besteht darin, die Zeile ohne die Spalten mit Standardeinschränkungen zu erstellen, und dann die Spalten zu aktualisieren, um die Standardwerte durch die angegebenen Werte zu ersetzen (falls nicht null).

Angenommen, Col1 ist der Primärschlüssel und Col4 und Col5 haben eine Standardkontraintion

-- create initial row with default values
insert table1 (col1, col2, col3)
    values (@col1, @col2, @col3)

-- update default values, if supplied
update table1
    set col4 = isnull(@col4, col4),
        col5 = isnull(@col5, col5)
    where col1 = @col1

Wenn Sie möchten, dass die tatsächlichen Werte in die Tabelle übernommen werden ...

-- create initial row with default values
insert table1 (col1, col2, col3)
    values (@col1, @col2, @col3)

-- create a container to hold the values actually inserted into the table
declare @inserted table (col4 datetime, col5 varchar(50))

-- update default values, if supplied
update table1
    set col4 = isnull(@col4, col4),
        col5 = isnull(@col5, col5)
    output inserted.col4, inserted.col5 into @inserted (col4, col5)
    where col1 = @col1

-- get the values defaulted into the table (optional)
select @col4 = col4, @col5 = col5 from @inserted

Prost...

0
Allinuon

Die prägnanteste Lösung, die ich mir vorstellen könnte, ist, der Einfügung ein Update für die Spalte mit dem Standard zu folgen:

IF OBJECT_ID('tempdb..#mytest') IS NOT NULL DROP TABLE #mytest
CREATE TABLE #mytest(f1 INT DEFAULT(1), f2 INT)
INSERT INTO  #mytest(f1,f2) VALUES (NULL,2)
INSERT INTO  #mytest(f1,f2) VALUES (3,3)

UPDATE #mytest SET f1 = DEFAULT WHERE f1 IS NULL

SELECT * FROM #mytest
0
Roy Fulbright

Mit genügend Standardwerten für einen Tisch können Sie einfach sagen:

INSERT t DEFAULT VALUES

Beachten Sie, dass dies jedoch ein ziemlich unwahrscheinlicher Fall ist. 

Ich musste es nur einmal in einer Produktionsumgebung verwenden. Wir hatten zwei eng miteinander verknüpfte Tabellen und mussten sicherstellen, dass keine der beiden Tabellen die gleiche UniqueID aufwies. Daher hatten wir eine separate Tabelle, die nur eine Identitätsspalte enthielt, und der beste Weg zum Einfügen war die obige Syntax.

0
Jonathan

Die weitaus beste Option ist, einen INSTEAD OF INSERT-Trigger für Ihre Tabelle zu erstellen, die Standardwerte aus Ihrer Tabelle zu entfernen und sie in den Trigger zu verschieben.

Dies wird wie folgt aussehen:

create trigger dbo.OnInsertIntoT
ON TablenameT
INSTEAD OF INSERT
AS
insert into TablenameT
select
   IsNull(column1 ,<default_value>)
  ,IsNull(column2 ,<default_value>)
  ...
from inserted

Auf diese Weise funktioniert es auf keinen Fall, welcher Code versucht, NULL-Werte in Ihre Tabelle einzufügen, verhindert gespeicherte Prozeduren, ist vollständig transparent und Sie müssen Ihre Standardwerte nur an einem Ort, nämlich diesem Auslöser, aufbewahren.

0
Blade

Sie können die COALESCE-Funktion in MS SQL verwenden.

INSERT in t (Wert) WERTE (COALESCE (@Wert, 'etwas'))

Ich persönlich bin nicht verrückt nach dieser Lösung, da es ein Alptraum für die Wartung ist, wenn Sie den Standardwert ändern möchten.

Meine Präferenz wäre der Vorschlag von Mitchel Sellers, aber das funktioniert nicht in MS SQL. Kann nicht mit anderen SQL-DBs sprechen.

0
Paul Osterhout

Hoffnung Um zu helfen -newbie as i am- Ones Ones, der Upsert-Anweisungen in MSSQL verwendet. (Dieser Code habe ich in meinem Projekt auf MSSQL 2008 R2 verwendet und funktioniert einfach perfekt .. Möglicherweise ist es nicht die beste Methode. Die Ausführungszeitstatistiken zeigen die Ausführung Zeit als 15 Millisekunden mit Einfügeanweisung) 

Setzen Sie einfach das Feld "Standardwert oder Bindung" Ihrer Spalte als das, was Sie als Standardwert für Ihre Spalte verwenden möchten, und legen Sie außerdem fest, dass die Spalte keine Nullwerte aus dem Entwurfsmenü akzeptieren soll, und erstellen Sie diese gespeicherte Prozedur.

`USE [YourTable]
GO


SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE PROC [dbo].[YourTableName]

    @Value smallint,
    @Value1 bigint,
    @Value2 varchar(50),
    @Value3 varchar(20),
    @Value4 varchar(20),
    @Value5 date,
    @Value6 varchar(50),
    @Value7 tinyint,
    @Value8 tinyint,
    @Value9 varchar(20),
    @Value10 varchar(20),
    @Value11 varchar(250),
    @Value12 tinyint,
    @Value13 varbinary(max) 

- In meinem Projekt @ Value13 befindet sich eine Fotospalte, die als Byte-Array speichert ..-- Und ich hatte vor, ein Standardfoto zu verwenden, wenn kein Foto übergeben wurde --, um es in db zu speichern. 

AS
--SET NOCOUNT ON
IF @Value = 0 BEGIN
    INSERT INTO YourTableName (
        [TableColumn1],
        [TableColumn2],
        [TableColumn3],
        [TableColumn4],
        [TableColumn5],
        [TableColumn6],
        [TableColumn7],
        [TableColumn8],
        [TableColumn9],
        [TableColumn10],
        [TableColumn11],
        [TableColumn12],
        [TableColumn13]
    )
    VALUES (
        @Value1,
        @Value2,
        @Value3,
        @Value4,
        @Value5,
        @Value6,
        @Value7,
        @Value8,
        @Value9,
        @Value10,
        @Value11,
        @Value12,
        default
    )
    SELECT SCOPE_IDENTITY() As InsertedID
END
ELSE BEGIN
    UPDATE YourTableName SET 
        [TableColumn1] = @Value1,
        [TableColumn2] = @Value2,
        [TableColumn3] = @Value3,
        [TableColumn4] = @Value4,
        [TableColumn5] = @Value5,
        [TableColumn6] = @Value6,
        [TableColumn7] = @Value7,
        [TableColumn8] = @Value8,
        [TableColumn9] = @Value9,
        [TableColumn10] = @Value10,
        [TableColumn11] = @Value11,
        [TableColumn12] = @Value12,
        [TableColumn13] = @Value13
    WHERE [TableColumn] = @Value

END
GO`
0
sihirbazzz

Adjunto table ejemplo. Prozedur für die Einschreibung Ejemplo ejecución: Ver valor DEFAULT en el paso al SP.

Das endgültige Ergebnis ist ein Fehler, der in der SP angezeigt wird. Misma técnica si no se quiere usar el SP= y hacer el INSERT (CAMPOS) VALUES (Standard) Ver que default es distinto a 'default' (con comillas)

    create Table Cliente_SeguimientoDeuda(IDRegistro int identity(1,1), Cliente int, ReferenciaReclamacion NVarChar(20) Default 'Reclamación', 
    Fecha DateTime, PersonaContactada nvarchar(30), Causa NVarChar(50), CompromisoObtenido NvarChar(50), 
    Usuario NVarChar(50), NotasReclamacion NVarChar(500),
    Primary Key (IDRegistro))


    create procedure NET_ADDReclamacion(@Cliente int, @ReferenciaReclamacion nvarchar(20)='por defecto' , 
    @Fecha datetime, @PersonaContactada nvarchar(30),@Causa nvarchar(50), @Compromiso nvarchar(50)
    , @Usuario nvarchar(50), @NotasReclamacion nvarchar(500))
    as
    set nocount on
    insert into Cliente_SeguimientoDeuda(Cliente, ReferenciaReclamacion,Fecha, PersonaContactada,Causa,CompromisoObtenido,
    Usuario, NotasReclamacion) Values (@Cliente,@ReferenciaReclamacion,@Fecha,@PersonaContactada,@Causa,@Compromiso,
    @Usuario,@NotasReclamacion)
    select @@IDENTITY

NET_ADDReclamacion 1,default,'01-01-2019','roberto','causa','compromiso','usu','notas'
0
R.Alonso