Как создать и использовать параметр «out» с базой данных SQL Server - PullRequest
0 голосов
/ 30 мая 2019

Я работаю над настольным приложением C #. Я хочу использовать хранимую процедуру (вставить запрос), чтобы добавить новую запись в таблицу данных. Мне нужно вернуть первичный ключ, который является идентификационной вставкой (bigint), чтобы избежать повторного обращения к базе данных. Я искал файлы справки MS (меньше) в течение нескольких часов и ничего не нашел о том, как установить параметр out хранимой процедуры или как получить возвращаемое значение.

Ответы [ 4 ]

1 голос
/ 30 мая 2019

То, что вы хотите, это OUTPUT Параметр. Я не разработчик C #, поэтому я опустил сторону C # и связал ответ:

--Sample Table
CREATE TABLE dbo.YourTable (ID bigint IDENTITY,
                            SomeColumn varchar(20));

GO
--Sample SP
CREATE PROC dbo.InsertYourTable @SomeColumn varchar(20), @ID bigint OUTPUT AS
BEGIN

    DECLARE @IDt table (ID bigint);

    INSERT INTO dbo.YourTable(SomeColumn)
    OUTPUT inserted.ID INTO @IDt
    VALUES(@SomeColumn);

    SET @ID = (SELECT ID FROM @IDt);
END;

GO
--Sample EXEC of proc and PRINT of OUTPUT value of ID
DECLARE @SomeColumn varchar(20) = 'abc', @ID bigint;

EXEC dbo.InsertYourTable @SomeColumn = @SomeColumn,
                         @ID = @ID OUTPUT;

PRINT @ID;

Используя этот ответ Я думаю, что c # будет:

cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("@SomeColumn",SqlDbType.VarChar,20);
cmd.Parameters["@SomeColumn"].Value = MyColumn;
cmd.Parameters.Add("@ID",SqlDbType.int).Direction = ParameterDirection.Output;
0 голосов
/ 31 мая 2019

с помощью вас, ребята, которые ответили, я наконец понял это.Я изменил хранимую процедуру следующим образом:


// Хранимая процедура

```` -- Add the parameters for the stored procedure here
````@Vendorcode nvarchar(17) = ''
````, @Name nvarchar(60) = ''
````...
````, @ID bigint output  --<<<<<<<<Added this line
````AS
````BEGIN
````    -- SET NOCOUNT ON added to prevent extra result sets from
````    -- interfering with SELECT statements.
````    SET NOCOUNT ON;
````    -- Insert statements for procedure here
````INSERT INTO APVendorShipTo
````        (Vendorcode, [Name], ...)
````VALUES  (@Vendorcode, @Name,...)

````Select @ID = SCOPE_IDENTITY(); -- <<<<<<<< Added this line
````END
*//end Stored Procedure*
----------


----------

*//C# Code in Desktop App*

````try
````{
````string connString = AdoHelper.ConnectionString;
````var myConnection = new SqlConnection(connString);
````var myCommand = new SqlCommand();
````using (myConnection)
````{
```` myConnection.Open();
```` myCommand.Connection = myConnection;
```` myCommand.CommandType = CommandType.StoredProcedure;
```` myCommand.CommandTimeout = 540;
```` myCommand.CommandText = "APVendorShipToAddNew";     
```` myCommand.Parameters.AddWithValue(parameterName: "@Vendorcode", value:   
this.txtAcctNo.Text);
```` myCommand.Parameters.AddWithValue(parameterName: "@Name", value: this.txtShipName.Text);
-- left out the rest of the parameters
--//Added the line below to retrieve the Identity Insert value from the query
````myCommand.Parameters.Add("@ID", SqlDbType.BigInt).Direction = ParameterDirection.Output;

````myCommand.ExecuteNonQuery();

--//Added next line to convert the returned value to a usable value in my program.
````liID = Convert.ToInt64(myCommand.Parameters["@ID"].Value);

````MessageBox.Show(Convert.ToString(liID)); 
--//Showed correct value Now available to  my code

````return true;
````}





0 голосов
/ 30 мая 2019

Использование предложения OUTPUT в INSERT - это замечательно и важно, если вам нужно захватить значения идентификаторов в многострочном пакете.Однако для начинающего SQL код немного сложнее, и в связи с этим конкретным вопросом его можно спутать с параметром OUTPUT хранимого процесса, который является совершенно не связанной концепцией.

Однако для вставки в одну строку функция SCOPE_IDENTITY прекрасно работает и ее проще использовать.

Вот версия хранимой процедуры Larnu с использованием вместо нее SCOPE_IDENTITY:

CREATE PROC dbo.InsertYourTable @SomeColumn varchar(20), @ID bigint OUTPUT AS
BEGIN

INSERT INTO dbo.YourTable(SomeColumn)
VALUES(@SomeColumn);

SET @ID = SCOPE_IDENTITY();
END;
0 голосов
/ 30 мая 2019

У меня сложилось впечатление, что вы пытаетесь перейти от трех поездок туда-сюда, например:

INSERT => SELECT to get key => OTHER INSERT using previous key

до двух

INSERT returns the key => OTHER INSERT using previous key

Мы можем сделать лучше.

Одним из способов решения этой проблемы является отправка более чем одной команды в строке sql из C #.Таким образом, в итоге получается нечто подобное, что позволяет избежать лишних циклических обращений к базе данных:

string sql = @"
   DECLARE @ID int; 
   EXEC InsertProcedure; 
   SELECT @ID = scope_identity(); 
   INSERT INTO OtherTable VALUES (@ID);";

using (var cn = new SqlConnection("connection string"))
using (var cmd = new SqlCommand(sql, cn))
{
    cn.Open();
    cmd.ExecuteNonQuery();
}

В качестве альтернативы, возможно, вам просто нужен ключ для использования в вашем приложении, поэтому вы можете продолжитьработать с записью и быстро искать через это новое значение кластерного индекса.В этом случае вы все равно можете сделать это следующим образом:

string sql = @"
   DECLARE @ID int; 
   EXEC InsertProcedure; 
   SELECT scope_identity();";

using (var cn = new SqlConnection("connection string"))
using (var cmd = new SqlCommand(sql, cn))
{
    cn.Open();
    return (int)cmd.ExecuteScalar();
}

Просто будьте осторожны, если у хранимой процедуры есть какие-либо собственные неразрешенные запросы выбора, в этом случае вам нужно будет использовать ExecuteReader(),наряду с его NextResult() методом для продвижения между SELECT результатами запроса.

Конечно, скорее всего, в этом есть нечто большее, чем в вашем реальном коде, где вам нужны параметры для вставки новых данных, но этообеспечивает общую концепцию.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...