Почему сервер SQL передает значение переменной OUTPUT в хранимой процедуре?

У меня есть функция, которая вызывает хранимую процедуру с предоставлением ее параметров.

int8 CDBAgent::CreateKnights(uint16 sClanID, uint8 bNation, string & strKnightsName, string & strChief, uint8 bFlag)
{
int8 bRet = -1;
unique_ptr<OdbcCommand> dbCommand(m_GameDB->CreateCommand());
if (dbCommand.get() == nullptr)
return bRet;dbCommand->AddParameter(SQL_PARAM_OUTPUT, &bRet);
dbCommand->AddParameter(SQL_PARAM_INPUT, strKnightsName.c_str(), strKnightsName.length());
dbCommand->AddParameter(SQL_PARAM_INPUT, strChief.c_str(), strChief.length());

if (!dbCommand->Execute(string_format(_T("{? = CALL CREATE_KNIGHTS ( %d, %d, %d, ?, ?)}"), sClanID, bNation, bFlag)))
ReportSQLError(m_GameDB->GetError());return bRet;
}

и хранимая процедура;

USE [KN_online]
GO
/****** Object:  StoredProcedure [dbo].[CREATE_KNIGHTS]    Script Date: 09/04/2016 03:09:46 ******/
SET ANSI_NULLS OFF
GO
SET QUOTED_IDENTIFIER ON
GO
-- Batch submitted through debugger: SQLQuery4.sql|7|0|C:\Users\Leth\AppData\Local\Temp\~vs3286.sql

/****** Object:  Stored Procedure dbo.CREATE_KNIGHTS    Script Date: 6/6/2006 6:03:32 PM ******/

-- modify by sungyong 2002.09.27

ALTER PROCEDURE [dbo].[CREATE_KNIGHTS]
@nRet       smallint OUTPUT,
@index      smallint,
@nation     tinyint,
@community  tinyint,
@strName    char(21),
@strChief   char(21)AS

DECLARE @Row tinyint, @knightsindex smallint, @knightsname char(21)
SET @Row = 0    SET @knightsindex = 0  SET @knightsname = ''

SELECT @Row = COUNT(*) FROM KNIGHTS WHERE IDNum = @index or  IDName = @strName

IF @Row > 0 or @index = 0
BEGIN
SET @nRet =  3
RETURN
END

--SELECT @Row = COUNT(*) FROM KNIGHTS WHERE IDName = @strName

--IF @Row > 0
--  BEGIN
--  SET @nRet =  3
--RETURN
--  END

BEGIN TRAN

INSERT INTO KNIGHTS ( IDNum, Nation, Flag, IDName, Chief  )
VALUES   (@index, @nation, @community, @strName, @strChief )

INSERT INTO KNIGHTS_USER ( sIDNum, strUserID  )
VALUES   (@index,  @strChief )

IF @@ERROR <> 0
BEGIN
ROLLBACK TRAN
SET @nRet =  6
RETURN
END

--  UPDATE USERDATA SET Knights = @index, Fame = 1 WHERE strUserId = @strChief  -- 1 == Chief Authority

IF @@ERROR <> 0
BEGIN
ROLLBACK TRAN
SET @nRet =  6
RETURN
END

COMMIT TRAN
SET @nRet =  0

Проблема в том, что когда хранимая процедура вызывается, она передает значение sClanID в bRet, что я и нашел, выполнив инструкцию непосредственно на SQL-сервере (2008 R2), потому что, когда я выполняю напрямую подобное;

exec CREATE_KNIGHTS 15001, 2, 1, "OpenKO", 'test'

он пытается преобразовать char (OpenKO) в tinyint, и если я даю число как strName вместо OpenKO, он говорит, что процедура ожидает параметр @strChief, который не был предоставлен.

У меня есть другие функции с такой же структурой, и они прекрасно подходят для правильного выбора параметров и возврата результатов, но почему это не так? и как я могу решить это?

Если вам нравится, вы можете увидеть весь проект на GitHub

Для SEO на этот вопрос, как я упоминал ниже, если я ввожу sClanID в виде слов, он выдает ошибку «Ошибка преобразования типа данных char в tinyint», а если я ввожу числа, он дает «Ожидается параметр @statement, который не был указан» «

0

Решение

Лучше всего ставить объявление параметров OUTPUT всегда в конце и вызывать SP с именами параметров.

ALTER PROCEDURE [dbo].[CREATE_KNIGHTS]
@index      smallint,
@nation     tinyint,
@community  tinyint,
@strName    char(21),
@strChief   char(21),
@nRet       smallint OUTPUT

Следующее утверждение должно измениться так:

if (!dbCommand->Execute(string_format(_T("{CALL CREATE_KNIGHTS ( %d, %d, %d, ?, ?, ?)}"), sClanID, bNation, bFlag)))

И код должен быть таким;

    dbCommand->AddParameter(SQL_PARAM_INPUT, strKnightsName.c_str(), strKnightsName.length());
dbCommand->AddParameter(SQL_PARAM_INPUT, strChief.c_str(), strChief.length());
dbCommand->AddParameter(SQL_PARAM_OUTPUT, &bRet);
1

Другие решения

Хотя мне удалось решить мой вопрос, я не приму мой собственный ответ, так как я ищу ответ в соответствии с его причиной.

Я решил это, просто передав первый параметр как bRet команде ODBC, так что последняя версия кода была;

int8 CDBAgent::CreateKnights(uint16 sClanID, uint8 bNation, string & strKnightsName, string & strChief, uint8 bFlag)
{
int8 bRet = -1;
unique_ptr<OdbcCommand> dbCommand(m_GameDB->CreateCommand());
if (dbCommand.get() == nullptr)
return bRet;dbCommand->AddParameter(SQL_PARAM_OUTPUT, &bRet);
dbCommand->AddParameter(SQL_PARAM_INPUT, strKnightsName.c_str(), strKnightsName.length());
dbCommand->AddParameter(SQL_PARAM_INPUT, strChief.c_str(), strChief.length());

if (!dbCommand->Execute(string_format(_T("{? = CALL CREATE_KNIGHTS (%d, %d, %d, %d, ?, ?)}"), bRet, sClanID, bNation, bFlag)))
ReportSQLError(m_GameDB->GetError());return bRet;
}

Поскольку проблема возникла из-за сдвига параметров при передаче значений в SP, просто передача начального значения переменной OUTPUT решила проблему.

0

По вопросам рекламы [email protected]