web-dev-qa-db-ja.com

パラメータがnullの場合にデフォルト値を挿入

デフォルト値を持つ列を持つテーブルがあります:

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

ストアドプロシージャを使用して、このテーブルに値を挿入しています。

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

質問は、@valuenullであるときにデフォルトを使用するにはどうすればよいですか?私は試した:

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

それは明らかにうまくいきませんでした。 caseステートメントも試してみましたが、それもうまくいきませんでした。他の提案はありますか?私はこれについて間違った方法で行っていますか?

更新:これを達成しようとしていますwithoutする必要があります:

  1. default値を複数の場所で維持し、
  2. 複数のinsertステートメントを使用します。

これが不可能な場合は、それと一緒に生活しなければならないと思います。これは何か達成できるはずです。

注:実際のテーブルには複数の列があります。私はすぐに例を書いていました。

39
chrisofspades

Ifステートメントを試してください...

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

クリストフ、

列のデフォルト値は、INSERTステートメントで列を指定しない場合にのみ適用されます。

Insertステートメントで明示的に列をリストし、明示的にNULLに設定しているので、それはその列のデフォルト値をオーバーライドしています

あなたがする必要があるのは、「nullがsprocに渡された場合、その列に挿入しようとしないでください」です。

これは、いくつかの動的SQLでそれを行う方法の簡単で厄介な例です。

デフォルト値を持ついくつかの列を持つテーブルを作成...

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

入力パラメーターに基づいて挿入ステートメントを動的に構築および実行するSPROCを作成します

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

次の2つのコマンドは、出力として必要なものの例を提供します...

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

私はこれがあなたがする必要があることをする非常に複雑な方法であることを知っています。おそらく、関連する列のInformationSchemaからデフォルト値を選択することもできますが、正直なところ、プロシージャの上部にあるparamにデフォルト値を追加することを検討するかもしれません

11
Eoin Campbell

私の知る限り、デフォルト値はinsertステートメントで値を指定しない場合にのみ挿入されます。したがって、たとえば、3つのフィールドを持つテーブルで次のようなことを行う必要があります(value2がデフォルト設定されています)

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

そして、value2がデフォルトになります。たぶん、誰かが単一のフィールドを持つテーブルのためにこれを達成する方法でチャイムするでしょう。

3
Brian Hasden

chrisofspades、

私の知る限り、振る舞いはdbエンジンの動作と互換性がありませんが、DO NOTの2つの目的を達成するための簡単な(エレガントであるかどうかはわかりませんが)解決策があります=

  1. 複数の場所でデフォルト値を維持し、そして
  2. 複数の挿入ステートメントを使用します。

解決策は、2つのフィールドを使用することです。1つは挿入可能、もう1つは選択に対して計算されます。

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

この方法では、パラメーターテーブルでビジネスのデフォルトの管理を一元化し、これを行うためのアドホック関数を配置して、vgを変更することもできます。

selValue AS ISNULL(insValue, 'something')

for

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

これがお役に立てば幸いです。

2

おそらく最もパフォーマンスにやさしい方法ではありませんが、テーブル名と列名を使用して情報スキーマからプルするスカラー関数を作成し、前に試したisnullロジックを使用して呼び出すことができます。

    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

そして、次のように呼び出します:

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

これが私が思いつく最高の方法です。 SQLインジェクションが挿入ステートメントを1つだけ使用するのを防ぎ、より多くのcaseステートメントで拡張できます。

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

ストアドプロシージャのパラメーターにデフォルト値を使用できます。

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

END

@ MyParam2が指定されていない場合、「ABC」値が設定されます...

1
CMS

挿入時に列または値を指定しないでください。デフォルトの制約の値が欠損値に置き換えられます。

これが単一の列テーブルでどのように機能するかわかりません。私は意味する:それはそうだろうが、それはあまり有用ではないだろう。

0
cfeduke

私が一般的に使用するパターンは、デフォルトの制約を持つ列なしで行を作成し、列を更新してデフォルト値を提供された値(nullでない場合)に置き換えることです。

Col1が主キーであり、col4とcol5にデフォルトの制約があると仮定します

-- 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

実際の値をテーブルにデフォルト設定する場合は...

-- 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

乾杯...

0
Allinuon

私が思いついた最も簡潔な解決策は、デフォルトの列の更新で挿入をフォローすることです:

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

テーブルに十分なデフォルトがある場合、次のように簡単に言うことができます。

INSERT t DEFAULT VALUES

ただし、これは非常にまれなケースです。

実稼働環境で一度使用するだけで済みました。密接に関連する2つのテーブルがあり、どちらのテーブルにも同じUniqueIDがないことを保証する必要があったため、ID列を持つ別のテーブルがあり、その構文を挿入する最良の方法は上記の構文を使用することでした。

0
Jonathan

最善のオプションは、テーブルのINSTEAD OF INSERTトリガーを作成し、テーブルからデフォルト値を削除して、それらをトリガーに移動することです。

これは次のようになります。

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

これにより、コードがテーブルにNULLを挿入しようとし、ストアドプロシージャを回避し、完全に透過的になり、デフォルト値を1か所、つまりこのトリガーで維持するだけで、問題なく動作します。

0
Blade

MS SQLでCOALESCE関数を使用できます。

INSERT INTO t(value)VALUES(COALESCE(@value、 'something'))

個人的には、デフォルト値を変更したい場合はメンテナンスの悪夢であるため、このソリューションには夢中ではありません。

私の好みはMitchel Sellersの提案ですが、それはMS SQLでは機能しません。他のSQL dbmsと通信できません。

0
Paul Osterhout

MSSQLでUpsertステートメントを使用する人に役立つことを願っています(このコードはMSSQL 2008 R2のプロジェクトで使用され、完全に機能します。ベストプラクティスではない可能性があります。実行時間の統計は実行を示します。挿入ステートメントで15ミリ秒の時間)

列の「デフォルト値またはバインディング」フィールドを、列のデフォルト値として使用することを決定したものとして設定し、また、列をデザインメニューからnull値を受け入れないように設定し、このストアドプロシージャを作成します。

`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) 

-私のプロジェクトでは@ Value13は写真の列で、バイト配列として保存されます。-そして、写真が渡されていないときにデフォルトの写真を使用することを計画しました-spに保存します。

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

付属テーブルejemplo。挿入手順例:既定値とデフォルト値.

最終結果は、SPの最終目標となる。誤った使用方法はありません。SP y y cercer INSERT(CAMPOS)VALUES(デフォルト)Ver que default es distinto to '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