2014-01-29 4 views
2

Я передаю список IdS как VARCHAR (500) и на основе того, что IdS записи являются required.My код SQL являетсяКак получить результат на основе списка идентификаторов, прошедших как varchar?

declare @Ids varchar(500) = '12964,12965,12966' 

select * 
from tblBooks 
where BookID in (@Ids) 

где BookID является VARCHAR (50) .Number ИДС может быть 100.Converting @ Идентификаторы в междунар дает следующее сообщение об ошибке

Конверсия удалось при преобразовании значения VARCHAR «12964,12965,12966» к типу данных междунар

Как я найти результат, как @Id не преобразуются в к Int.

+0

Если 'id' является целым числом, то почему вы пытаетесь пройти их как «варчар»? –

+0

Я прохожу через приложение C#. – Mickel

+2

http://www.sommarskog.se/arrays-in-sql-2008.html –

ответ

7

Используйте табличную переменную:

DECLARE @Ids TABLE (ID INT); 
INSERT @Ids VALUES (12964),(12965),(12966); 

SELECT * 
FROM tblBooks 
WHERE BookID in (SELECT ID FROM @Ids); 

Если вам нужно передать это в порядке, то вы можете использовать таблицу оцененный параметр:

CREATE TYPE dbo.ListOfInt AS TABLE (ID INT); 
GO 
CREATE PROCEDURE dbo.GetBooks @IDs dbo.ListOfInt READONLY 
AS 
BEGIN 
    SELECT * 
    FROM tblBooks 
    WHERE BookID in (SELECT ID FROM @Ids); 
END 
GO 

DECLARE @IDs dbo.ListofInt; 
INSERT @Ids VALUES (12964),(12965),(12966); 
EXECUTE dbo.GetBooks @Ids; 

Или От C#

var table = new DataTable(); 
table.Columns.Add("ID", typeof(int)); 

// ADD YOUR LIST TO THE TABLE 

using (var connection = new SqlConnection("Connection String")) 
using (var command = new SqlCommand("dbo.GetBooks", connection)) 
{ 
    command.CommandType = CommandType.StoredProcedure; 
    var param = new SqlParameter("@Ids", SqlDbType.Structured); 
    param.TypeName = "dbo.ListofInt"; 
    param.Value = table; 
    command.Parameters.Add(table); 
    connection.Open(); 

    using (var reader = command.ExecuteReader()) 
    { 
     while (reader.Read()) 
     { 
      // do something 
     } 
    } 
} 

Как только ТИП находится на месте, вам даже не нужно использовать хранимую процедуру. Вы можете просто вызвать обычный запрос:

using (var connection = new SqlConnection("Connection String")) 
using (var command = new SqlCommand("SELECT * FROM tblBooks WHERE BookID IN (SELECT ID FROM @IDs)", connection)) 
{ 
    var param = new SqlParameter("@Ids", SqlDbType.Structured); 
    param.TypeName = "dbo.ListofInt"; 
    param.Value = table; 
    command.Parameters.Add(table); 
    connection.Open(); 

    // ETC 
} 

Doing раскол в C# с помощью String.Split() и проходящего список в SQL будет более эффективным, чем любой подход, который делает раскол в SQL

+0

Это предпочтительный подход. Вы не показали, как это будет вызываться из приложения C#. Это будет очередной выпуск OP. – Yuck

+1

@Yuck Да, я только что видел это, уже писал редактирование, когда вы прокомментировали. – GarethD

2

Вы можете написать запрос, как это:

declare @Ids varchar(500) = '12964,12965,12966' 

select * 
from tblBooks 
where ','+cast(BookID as varchar(500))+',' like '%,'[email protected]+',%'; 

Но вы не хотите, чтобы сделать это, потому что производительность плохо - запрос не может использовать индексы.

Три других варианта. Используйте динамический SQL и подключите список непосредственно к запросу. Или используйте функцию split для разделения строки. Или использовать табличную переменную:

declare @ids table (id int); 
insert into @ids(id) 
    select 12964 union all select 12965 union all select 12966; 

select b.* 
from tblBooks b 
where b.BookId in (select id from @ids); 
2

Это не будет работать , SQL Server не разделяет строки для вас неявно и не существует встроенной функции разделения строк в SQL Server.

Если вы управляете этим через C#, вы можете использовать параметры значения таблицы. Вы также можете передать свой запрос через Dapper-Dot-Net, который автоматически параметризует запрос «В».

Если вы действительно должны это сделать в T-SQL, вы также можете использовать логику разделения строк здесь, является относительно кратким.

SELECT i.value('./text()[1]', 'int') [id] into #ids 
FROM(values(CONVERT(xml,'<r>' + REPLACE(@Ids+left(@@dbts,0),',','</r><r>') + '</r>'))) a(_) 
CROSS APPLY _.nodes('./r') x(i) 
select * 
from tblBooks a 
join #ids i on i.id = a.bookId 
0

Создать эту функцию:

CREATE FUNCTION [dbo].[SplitDelimiterString] (@StringWithDelimiter VARCHAR(8000), @Delimiter VARCHAR(8)) 

RETURNS @ItemTable TABLE (Item VARCHAR(8000)) 

AS 
BEGIN 
    DECLARE @StartingPosition INT; 
    DECLARE @ItemInString VARCHAR(8000); 

    SELECT @StartingPosition = 1; 
    --Return if string is null or empty 
    IF LEN(@StringWithDelimiter) = 0 OR @StringWithDelimiter IS NULL RETURN; 

    WHILE @StartingPosition > 0 
    BEGIN 
     --Get starting index of delimiter .. If string 
     --doesn't contain any delimiter than it will returl 0 
     SET @StartingPosition = CHARINDEX(@Delimiter,@StringWithDelimiter); 

     --Get item from string   
     IF @StartingPosition > 0     
      SET @ItemInString = SUBSTRING(@StringWithDelimiter,0,@StartingPosition) 
     ELSE 
      SET @ItemInString = @StringWithDelimiter; 
     --If item isn't empty than add to return table  
     IF(LEN(@ItemInString) > 0) 
      INSERT INTO @ItemTable(Item) VALUES (@ItemInString);    

     --Remove inserted item from string 
     SET @StringWithDelimiter = SUBSTRING(@StringWithDelimiter,@StartingPosition + 
        LEN(@Delimiter),LEN(@StringWithDelimiter) - @StartingPosition) 

     --Break loop if string is empty 
     IF LEN(@StringWithDelimiter) = 0 BREAK; 
    END 

    RETURN 
END 

Затем вызовите его следующим образом:

declare @Ids varchar(500) = '12964,12965,12966' 

select * 
from tblBooks 
where BookID in (SELECT * FROM dbo.SplitDelimiterString(@ids,',')) 
+0

Интересное решение. Наверное, это не самая эффективная вещь в мире, но это нелепость для выполнения работы. – RubberDuck

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