Ошибка при использовании строки CSV с оператором IN - PullRequest
2 голосов
/ 10 августа 2010

Когда я запускаю следующий код

declare @aaa nvarchar(10)
set @aaa='1,2,3'
Select * from Customer where CustomerId in (convert(nvarchar,@aaa,10))

, я получаю эту ошибку

Msg 8114, Level 16, State 5, Line 3
Error converting data type nvarchar to bigint.

plz help

Ответы [ 5 ]

6 голосов
/ 10 августа 2010

Вы не можете использовать IN со строкой cvs. Если у вас Sql Server 2008, вы можете использовать параметр табличных значений (новый в SQL Server 2008). Настройте его, создав фактический тип параметра таблицы:

CREATE TYPE IntTableType AS TABLE (ID bigint PRIMARY KEY)

Ваша процедура будет тогда:

Create Procedure up_TEST
    @Ids IntTableType READONLY
AS

SELECT * 
    from Customer where CustomerId in (SELECT ID FROM @Ids)

RETURN 0
GO

если вы не можете использовать параметры табличных значений, см .: «Массивы и списки в SQL Server 2008 с использованием табличных параметров» от Erland Sommarskog , тогда существует много способов разбить строку в SQL Server , В этой статье рассматриваются преимущества и недостатки практически каждого метода:

"Массивы и списки в SQL Server 2005 и более поздних версиях, когда параметры табличных значений не обрезают его", Эрланд Соммарског

Вам необходимо создать функцию разделения. Вот как можно использовать функцию разделения:

SELECT
    *
    FROM YourTable                               y
    INNER JOIN dbo.yourSplitFunction(@Parameter) s ON y.ID=s.Value

Я предпочитаю подход с использованием таблиц чисел для разделения строки в TSQL , но существует множество способов разделения строк в SQL Server, см. Предыдущую ссылку, в которой объясняются плюсы и минусы каждого из них.

Чтобы метод таблицы чисел сработал, необходимо выполнить настройку единой таблицы, которая создаст таблицу Numbers, содержащую строки от 1 до 10 000:

SELECT TOP 10000 IDENTITY(int,1,1) AS Number
    INTO Numbers
    FROM sys.objects s1
    CROSS JOIN sys.objects s2
ALTER TABLE Numbers ADD CONSTRAINT PK_Numbers PRIMARY KEY CLUSTERED (Number)

После настройки таблицы Numbers создайте эту функцию разделения:

CREATE FUNCTION [dbo].[FN_ListToTable]
(
     @SplitOn  char(1)      --REQUIRED, the character to split the @List string on
    ,@List     varchar(8000)--REQUIRED, the list to split apart
)
RETURNS TABLE
AS
RETURN 
(

    ----------------
    --SINGLE QUERY-- --this will not return empty rows
    ----------------
    SELECT
        ListValue
        FROM (SELECT
                  LTRIM(RTRIM(SUBSTRING(List2, number+1, CHARINDEX(@SplitOn, List2, number+1)-number - 1))) AS ListValue
                  FROM (
                           SELECT @SplitOn + @List + @SplitOn AS List2
                       ) AS dt
                      INNER JOIN Numbers n ON n.Number < LEN(dt.List2)
                  WHERE SUBSTRING(List2, number, 1) = @SplitOn
             ) dt2
        WHERE ListValue IS NOT NULL AND ListValue!=''

);
GO 

Теперь вы можете легко разбить строку CSV и использовать ее в своем запросе:

declare @aaa nvarchar(10)
set @aaa='1,2,3'
Select * from Customer where CustomerId in (SELECT ListValue FROM dbo.FN_ListToTable(',',@aaa))
1 голос
/ 10 августа 2010

Вы должны использовать определяемую пользователем функцию, чтобы разбить вашу строку на таблицу и использовать ее в предложении WHERE

Вот код для функции

DROP FUNCTION dbo.udf_ItemParse 
GO
CREATE FUNCTION dbo.udf_ItemParse 
(
    @Input VARCHAR(8000), 
    @Delimeter char(1)='|'
)
RETURNS @ItemList TABLE (
    Item VARCHAR(50) ,
    Pos int
)
AS
BEGIN

    DECLARE @Item varchar(50)
    DECLARE @StartPos int, @Length int
    DECLARE @Pos int

    SET @Pos = 0

    WHILE LEN(@Input) > 0
    BEGIN

        SET @StartPos = CHARINDEX(@Delimeter, @Input)

        IF @StartPos < 0 SET @StartPos = 0

        SET @Length = LEN(@Input) - @StartPos - 1

        IF @Length < 0 SET @Length = 0

        IF @StartPos > 0
        BEGIN
            SET @Pos = @Pos + 1
            SET @Item = SUBSTRING(@Input, 1, @StartPos - 1)
            SET @Input = SUBSTRING(@Input, @StartPos + 1, LEN(@Input) - @StartPos)
        END
        ELSE
        BEGIN
            SET @Pos = @Pos+1
            SET @Item = @Input
            SET @Input = ''
        END

        INSERT @ItemList (Item, Pos) VALUES(@Item, @Pos)
    END
    RETURN
END 
GO

Вот как это можно использовать

declare @aaa nvarchar(10)
set @aaa='1,2,3'
Select * from Customer 
where 
CustomerId in (SELECT Item From Udf_ItemParse(@aaa, ','))
1 голос
/ 10 августа 2010

Вы не можете передать CSV в IN таким образом. IN ожидает 1,2,3, а не '1,2,3', что является огромной разницей.

Если у вас есть CSV, вам нужно создать функцию, которая разбивает CSV на таблицу и передаст результат в IN. В SQL Server такой функции не существует "из коробки".

Существует множество решений для этого онлайн, хотя. Вот один .

Выдержка из ссылки

CREATE FUNCTION dbo.SplitCSV (@CSVString VARCHAR(8000), @Delimiter CHAR(1))
RETURNS @temptable TABLE (items VARCHAR(8000))
AS

BEGIN

DECLARE @pos INT;
DECLARE @slice VARCHAR(8000);

SELECT @pos = 1;
IF LEN(@CSVString) < 1 OR @CSVString IS NULL RETURN;

WHILE @pos!= 0
BEGIN
SET @pos = CHARINDEX(@Delimiter,@CSVString);
IF @pos != 0
SET @slice = LEFT(@CSVString, @pos - 1);
ELSE
SET @slice = @CSVString;

IF( LEN(@slice) > 0)
INSERT INTO @temptable(Items) VALUES (@slice);

SET @CSVString = RIGHT(@CSVString, LEN(@CSVString) - @pos);
IF LEN(@CSVString) = 0 BREAK;
END
RETURN
END
0 голосов
/ 10 августа 2010
 Declare @SQL VarChar(1000)
 @SQL = 'Select * from Customer where CustomerId in (' + @aaa + ')'
 EXEC (@SQL)
0 голосов
/ 10 августа 2010

Значение 1,2,3 не может быть преобразовано в bigint.

И это нормально, потому что это значение nvarchar, которое вы пытаетесь сделать так:

Select * from Customer where CustomerId in (1,2,3)

Здесь Вы получаете три записи.

Выберите * из Customer, где CustomerId in ('1,2,3')

и здесь вы пытаетесь получить один объект.

Операция, которую Вы хотите выполнить, невозможна с этого nvarchar

функция convert может изменять только представление символов в nvarchar на представление чисел. и это не число, которое выглядит как 1,2,3

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