harish kashyap01 Ответов: 3

Ошибка преобразования при преобразовании значения varchar в тип данных int


ПРИВЕТ,

Я пытаюсь отфильтровать представление, основанное на "кодклиента".Но я получаю вышеуказанную ошибку .




"Ошибка преобразования в тип varchar значение 'и VU_CRM_Customers.CustomerID=' для типа данных int."

Что я уже пробовал:

CREATE PROCEDURE SP_Customer(@FromDate date, @ToDate date,@AccessLevelCode nvarchar(30)=NULL,@UserID nvarchar(30)=NULL ,@UserOrgBranchID int=NULL,@UserGroupID int=NULL,@CustomerID int=0)
AS
BEGIN
    SET NOCOUNT ON;
	DECLARE @CUSTOMERIDS varchar(30)=null
	DECLARE @SQL nvarchar(max);
	If(@CustomerID IS NOT NULL)
	BEGIN
	SET @CUSTOMERIDS= 'AND VU_CRM_Customers.CustomerID='+@CustomerID
	END
	ELSE
	BEGIN
	SET @CUSTOMERIDS= ''
	END
    SET @SQL=N'	
	DECLARE @Temp TABLE
	(
	    [Row] INT,
		Customer NVARCHAR(MAX),
		CustomerID int,
		TransactionType NVARCHAR(MAX),
      	VoucherDate smalldatetime,
      	VoucherNo NVARCHAR(MAX),
		AccountingDate datetime,
		Amount numeric(18,3),
		Debit numeric(18,3),
		Credit numeric(18,3),		
		[OrgID] INT
	);
	
	INSERT INTO @Temp 
    SELECT ROW_NUMBER() OVER(PARTITION BY Customer ORDER BY CreatedDate) AS Row,* FROM
    (SELECT CASE WHEN ISNULL(ISNULL(Mobile,Phone),'''')='''' THEN Customer ELSE CONCAT(Customer,''('',ISNULL(Mobile,Phone),'')'') END AS Customer,
	''Opening Balance'' AS TransactionType,AccountingDate AS VoucherDate,COALESCE(ACC_FinOpeningBalance.ReferenceNo, CONVERT(nvarchar,OpeningBalanceID)) AS VoucherNo,AccountingDate AS CreatedDate,CASE WHEN Dr>0 THEN Dr ELSE Cr END AS Amount,Dr AS Debit,Cr AS Credit,ACC_FinOpeningBalance.OrgID
	FROM ACC_FinOpeningBalance INNER JOIN VU_CRM_Customers ON  ACC_FinOpeningBalance.SLGroupCode=''C'' 
	AND ACC_FinOpeningBalance.SubledgerID=VU_CRM_Customers.CustomerID
	WHERE ACC_FinOpeningBalance.CreatedBy' +[dbo].[fnGetAccessFilter]( @AccessLevelCode,@UserID ,@UserOrgBranchID,@UserGroupID) +   @CUSTOMERIDS + '
	UNION
	SELECT CASE WHEN ISNULL(ISNULL(Mobile,Phone),'''')='''' THEN Customer ELSE CONCAT(Customer,''('',ISNULL(Mobile,Phone),'')'') END AS Customer,
    ''Advance'' AS TransactionType,AdvanceDate AS VoucherDate,COALESCE(ACC_AdvanceReceived.ReferenceNo, CONVERT(nvarchar,AdvanceReceivedID)) AS VoucherNo,AdvanceDate AS CreatedDate,NetReceivable AS Amount,NetReceivable AS Debit,0 AS Credit,ACC_AdvanceReceived.OrgID 
	FROM ACC_AdvanceReceived INNER JOIN VU_CRM_Customers ON ACC_AdvanceReceived.AccountID=VU_CRM_Customers.CustomerID
	WHERE Customer IS NOT NULL
	AND ACC_AdvanceReceived.CreatedBy' +[dbo].[fnGetAccessFilter]( @AccessLevelCode,@UserID ,@UserOrgBranchID,@UserGroupID) + @CUSTOMERIDS+'
     
	
	SELECT *,(M.OpeningBalance+M.Debit-M.Credit) AS ClosingBalance FROM
    (SELECT L.Row,L.Customer,L.TransactionType,L.VoucherDate,L.VoucherNo,L.AccountingDate,L.Amount,L.OrgID,
    ISNULL((SELECT SUM(Debit)-SUM(Credit) FROM @Temp AS O WHERE O.AccountingDate<=L.AccountingDate AND O.Customer=L.Customer AND O.Row<L.Row),0) AS OpeningBalance,
    L.Debit,L.Credit FROM @Temp AS L WHERE L.AccountingDate  BETWEEN '''+CONVERT(nvarchar,@FromDate)+''' AND DATEADD(minute,59,DATEADD(hour,23,CONVERT(datetime, '''+CONVERT(nvarchar,@ToDate)+''')))) AS M ;';
EXEC sp_executesql @SQL;
print @SQL;
END

3 Ответов

Рейтинг:
2

OriginalGriff

Посмотрите на свой код:

SET @CUSTOMERIDS= 'AND VU_CRM_Customers.CustomerID='+@CustomerID
                  ^                                ^
                  |                                |
Эти цитаты делают AND VU_CRM_Customers.CustomerID= строковый литерал, и когда он пытается объединить его с целочисленным параметром, он пытается преобразовать строку и терпит неудачу.

Вероятно, все, что вам нужно сделать, это удалить кавычки ...


Рейтинг:
19

Richard Deeming

Гифф почти прав. Проблема в том, что вы пытаетесь добавить число к строковому литералу. Из-за правил преобразования типов SQL он пытается преобразовать строку в число, чтобы выполнить сложение.

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

SET @CUSTOMERIDS = 'AND VU_CRM_Customers.CustomerID = ' + CAST(@CustomerID As varchar(20))

Но это не очень хороший подход. Пока ты здесь возможно безопасно в данном конкретном случае, поскольку параметры являются либо числами, либо датами, использование конкатенации строк для построения SQL-запроса может сделать вас уязвимым для SQL-инъекция[^].

процедуры sp_executesql[^] дает вам гораздо более безопасный вариант: передать параметры в качестве параметров:
CREATE PROCEDURE SP_Customer(@FromDate date, @ToDate date, @AccessLevelCode nvarchar(30) = NULL, @UserID nvarchar(30) = NULL, @UserOrgBranchID int = NULL, @UserGroupID int = NULL, @CustomerID int = 0)
AS
BEGIN
DECLARE @SQL nvarchar(max), @params nvarchar(max);
DECLARE @AccessFilter nvarchar(max), @CustomerIDs nvarchar(max);

    SET NOCOUNT ON;
    SET @AccessFilter = dbo.fnGetAccessFilter(@AccessLevelCode, @UserID, @UserOrgBranchID, @UserGroupID);
    
    SET @CustomerIDs = CASE
        WHEN @CustomerID Is Null THEN N''
        ELSE N'AND VU_CRM_Customers.CustomerID = @CustomerID'
    END;

    SET @SQL = N'	
    DECLARE @Temp TABLE
    (
        [Row] INT,
        Customer NVARCHAR(MAX),
        CustomerID int,
        TransactionType NVARCHAR(MAX),
        VoucherDate smalldatetime,
        VoucherNo NVARCHAR(MAX),
        AccountingDate datetime,
        Amount numeric(18,3),
        Debit numeric(18,3),
        Credit numeric(18,3),        
        [OrgID] INT
    );
    
    INSERT INTO @Temp 
    SELECT 
        ROW_NUMBER() OVER(PARTITION BY Customer ORDER BY CreatedDate) AS Row, 
        * 
    FROM
        (
            SELECT 
                CASE 
                    WHEN ISNULL(ISNULL(Mobile,Phone),'''') = '''' THEN Customer 
                    ELSE CONCAT(Customer,''('',ISNULL(Mobile,Phone),'')'') 
                END AS Customer,
                ''Opening Balance'' AS TransactionType,
                AccountingDate AS VoucherDate,
                COALESCE(ACC_FinOpeningBalance.ReferenceNo, CONVERT(nvarchar,OpeningBalanceID)) AS VoucherNo,
                AccountingDate AS CreatedDate,
                CASE WHEN Dr > 0 THEN Dr ELSE Cr END AS Amount,
                Dr AS Debit,
                Cr AS Credit,
                ACC_FinOpeningBalance.OrgID
            FROM 
                ACC_FinOpeningBalance 
                INNER JOIN VU_CRM_Customers 
                ON ACC_FinOpeningBalance.SLGroupCode = ''C'' 
                AND ACC_FinOpeningBalance.SubledgerID = VU_CRM_Customers.CustomerID
            WHERE 
                ACC_FinOpeningBalance.CreatedBy' + @AccessFilter + @CustomerIDs + N'
            
            UNION
            
            SELECT 
                 CASE 
                     WHEN ISNULL(ISNULL(Mobile,Phone),'''')='''' THEN Customer 
                     ELSE CONCAT(Customer,''('',ISNULL(Mobile,Phone),'')'') 
                 END AS Customer,
                ''Advance'' AS TransactionType,
                 AdvanceDate AS VoucherDate,
                 COALESCE(ACC_AdvanceReceived.ReferenceNo, CONVERT(nvarchar,AdvanceReceivedID)) AS VoucherNo,
                 AdvanceDate AS CreatedDate,
                 NetReceivable AS Amount,
                 NetReceivable AS Debit,
                 0 AS Credit,
                 ACC_AdvanceReceived.OrgID 
            FROM 
                ACC_AdvanceReceived 
                INNER JOIN VU_CRM_Customers 
                ON ACC_AdvanceReceived.AccountID = VU_CRM_Customers.CustomerID
            WHERE 
                Customer IS NOT NULL
            AND 
                ACC_AdvanceReceived.CreatedBy' + @AccessFilter + @CustomerIDs + N'
        )
    ;
    
    SELECT 
        *,
        (M.OpeningBalance + M.Debit - M.Credit) AS ClosingBalance 
    FROM
        (
            SELECT 
                L.Row,
                L.Customer,
                L.TransactionType,
                L.VoucherDate,
                L.VoucherNo,
                L.AccountingDate,
                L.Amount,
                L.OrgID,
                ISNULL((SELECT SUM(Debit) - SUM(Credit) FROM @Temp AS O WHERE O.AccountingDate <= L.AccountingDate AND O.Customer = L.Customer AND O.Row < L.Row), 0) AS OpeningBalance,
                L.Debit,
                L.Credit 
            FROM 
                @Temp AS L 
            WHERE 
                L.AccountingDate  >= @FromDate 
            And 
                L.AccountingDate < @ToDate
        ) As M
    ;';
    
    SET @params = N'@FromDate date, @ToDate date, @CustomerID int';
    EXEC sp_executesql @SQL, @params, @FromDate = @FromDate, @ToDate = @ToDate, @CustomerID = @CustomerID;
    print @SQL;
END
NB: Вероятно, вы можете что-то сделать с возвращаемым значением fnGetAccessFilter но поскольку я не вижу кода для этой функции, я не могу вам сказать.

Особое примечание 2: Приведение в порядок вашего динамического запроса делает очевидным, что у вас есть несколько неуместных скобок. После исправления ошибки преобразования следующей ошибкой будет синтаксическая ошибка при попытке выполнить запрос. Я думаю, что исправил это, но вам, вероятно, следует проверить.

NB3: В зависимости от того, какую версию SQL Server вы используете, вероятно, существует гораздо более чистый способ создания текущих итогов. Если это 2012 год или более поздняя версия, вы можете использовать функция запаздывания[^].


Рейтинг:
1

harish kashyap01

ПРИВЕТ
@OriginalGriff

Спасибо за ответ
Я уже пробовал раньше.
Но я не могу построить утверждение без этих цитат.


Richard Deeming

В настоящее время существует ошибка, которая означает, что комментарии не отображаются. Но пожалуйста НЕ опубликуйте свой комментарий как "решение". Оставьте комментарий, и, надеюсь, он появится, как только ошибка будет исправлена.