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 @value
null
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:
default
-Wert an mehreren Stellen undinsert
-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.
Versuchen Sie eine if-Anweisung ...
if @value is null
insert into t (value) values (default)
else
insert into t (value) values (@value)
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
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.
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
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.
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') )
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
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' ...
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.
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...
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
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.
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.
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.
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`
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'