2015-02-18 1 views
2

Stored Proc:Ошибка преобразования типа данных NVARCHAR к BigInt вызвано оператором IN в хранимой процедуре

ALTER PROCEDURE [dbo].[MyProcedure] 
    @CommaSeperatedValues nvarchar(500) 
AS 
BEGIN 
    SET NOCOUNT ON; 
    SELECT Col1, Col2, Col3 
    FROM MyTable 
    WHERE SomeCol_BigIntDataType IN (@CommaSeperatedValues) 

Значение, которое исходит от кодекса значение строки: "9010073,9010074"

Я попытался запустить СП, как это: EXEC MyProcedure «9010073,9010074»

Это дает сообщение об ошибке «ошибка преобразования типа данных NVARCHAR в BigInt» во время работы SP

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

SELECT Col1, Col2, Col3 
    FROM MyTable 
    WHERE SomeCol_BigIntDataType IN (9010073,9010074) 

Затем я получаю ожидаемые результаты.

Но я хочу бежать из SP.

+0

Сначала вы должны преобразовать CVS в строки. –

+0

Вам нужно иметь функцию SplitString named, которая разделит строку на понятную строку SQL SERVER, которая затем может быть использована в операторе IN. Что-то вроде «Выберите часть из SplitString (@Values, ',') –

+1

Лучше использовать тип данных *, предназначенный * для хранения нескольких значений, таких как табличный параметр или даже xml, вместо того, чтобы набивать несколько значений в строка. SQL (как и большинство языков) не принимает ни одного строкового значения, обратите внимание, что он содержит запятые, а затем решил действовать так, как если бы вы фактически предоставили ему несколько значений. –

ответ

2

Создайте следующую табличную функцию как SplitString в базе данных. Когда вы хотите выбрать элементы; используйте это:

Select Part from SplitString(@YourValues, ',') 

Вышеуказанный оператор используется в вашем запросе.

SELECT Col1, Col2, Col3 
    FROM MyTable 
    WHERE SomeCol_BigIntDataType IN (Select Part from SplitString(@CommaSeperatedValues, ',')) 

Ниже приведена функция в вашей базе данных.

CREATE FUNCTION [dbo].[SplitString] 
(
    -- Add the parameters for the function here 
    @myString varchar(500), 
    @deliminator varchar(10) 
) 
RETURNS 
@ReturnTable TABLE 
(
    -- Add the column definitions for the TABLE variable here 
    [id] [int] IDENTITY(1,1) NOT NULL, 
    [part] [varchar](50) NULL 
) 
AS 
BEGIN 
     Declare @iSpaces int 
     Declare @part varchar(50) 

     --initialize spaces 
     Select @iSpaces = charindex(@deliminator,@myString,0) 
     While @iSpaces > 0 

     Begin 
      Select @part = 
substring(@myString,0,charindex(@deliminator,@myString,0)) 

      Insert Into @ReturnTable(part) 
      Select @part 

    Select @myString = 
substring(@mystring,charindex(@deliminator,@myString,0)+ 
len(@deliminator),len(@myString) - charindex(' ',@myString,0)) 


      Select @iSpaces = charindex(@deliminator,@myString,0) 
     end 

     If len(@myString) > 0 
      Insert Into @ReturnTable 
      Select @myString 

    RETURN 
END 
+0

Это более сложная и менее эффективная, чем функция Moden. TVPs еще лучше –

+1

Я вижу. Я посмотрю на это. Спасибо за ваше любезное предложение. –

1

У вас должна быть функция для разделения строк с разделителями-запятыми в отдельные строки. Затем вы вызываете функцию, как это:

SELECT 
    Col1, Col2, Col3 
FROM MyTable 
WHERE 
    SomeCol_BigIntDataType IN (
     SELECT CAST(Item AS BIGINT) 
     FROM dbo.[DelimitedSplitN4K](@CommaSeperatedValues, ',') 
) 

Вот DelimitedSplitN4K функции Джефф Moden. Для получения дополнительной информации: http://www.sqlservercentral.com/articles/Tally+Table/72993/

CREATE FUNCTION [dbo].[DelimitedSplitN4K](
    @pString NVARCHAR(4000), @pDelimiter NCHAR(1) 
) 
RETURNS TABLE WITH SCHEMABINDING AS 
RETURN 
WITH E1(N) AS (
    SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL 
    SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 
) 
,E2(N) AS (SELECT 1 FROM E1 a, E1 b) 
,E4(N) AS (SELECT 1 FROM E2 a, E2 b) 
,cteTally(N) AS(
    SELECT TOP (ISNULL(DATALENGTH(@pString)/2,0)) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E4 
) 
,cteStart(N1) AS(
    SELECT 1 UNION ALL 
    SELECT t.N+1 FROM cteTally t WHERE SUBSTRING(@pString,t.N,1) = @pDelimiter 
), 
cteLen(N1,L1) AS(
SELECT 
    s.N1, 
    ISNULL(NULLIF(CHARINDEX(@pDelimiter,@pString,s.N1),0)-s.N1,4000) 
FROM cteStart s 
) 
SELECT 
    ItemNumber = ROW_NUMBER() OVER(ORDER BY l.N1), 
    Item  = SUBSTRING(@pString, l.N1, l.L1) 
FROM cteLen l 
; 
GO 

ОТКАЗ: Комментарии удаляются из функции и форматирование было изменено.

5

Здесь мы идем. Вы можете сделать это с помощью Dynamic Query

DECLARE @mystring NVARCHAR(max) 
DECLARE @UserId NVARCHAR(max) 
SET @UserId = '9010073,9010074' 
SELECT @mystring = 'SELECT Col1, Col2, Col3 FROM MyTable where UserId IN('+ @UserId +')' 
EXEC sp_executesql @mystring 
+0

Самое элегантное решение. Хорошая работа – Anjani

Смежные вопросы