2013-04-16 2 views
1

У меня есть следующий запрос:Следует ли здесь использовать табличные параметры?

@"UPDATE students SET IsDeleted = 1 WHERE StudentId IN (
     SELECT StudentId FROM Class where PassId IN (
       SELECT Id FROM ClassValueTable WHERE IsDeleted <> 1" 
       + activeIds)))"; 

где activeIds = строка некоторых чисел, например: 1,2,3,4 ...

Я хочу, чтобы преобразовать этот запрос в хранимую процедуру. Мой вопрос в том, что является лучшим способом передать activeIds в качестве параметра этой хранимой процедуры?

* Код находится в C# и я использую 2008

+0

[табличные значения параметров] (http://msdn.microsoft.com/en-us/library/bb675163.aspx) (однако, я не знаю, знает ли C# 3 'SqlDbType.Structured') –

+0

@TimSchmelter - activeIds - это просто строка. Не могу ли я передать его как строку? – NoviceMe

+1

Не использовать и использовать табличные параметры. Почему это должна быть строка? Разве это не из коллекции в какой-то момент? Зачем конвертировать его в строку только для того, чтобы разбить ее на нестрочную? Если вы собираетесь это сделать, просто продолжайте использовать приложение для инъекций SQL, которое вы используете сейчас ... –

ответ

3

Да, использование таблицы многозначных параметров SQL Server. Сначала нужно создать тип:

CREATE TYPE dbo.StudentIDs(ID INT PRIMARY KEY); 

Теперь ваша процедура может использовать это (обратите внимание, что я изменил свои вложенные IN запросы к собственно присоединиться):

CREATE PROCEDURE dbo.MarkStudentsAsDeleted 
    @IDs dbo.StudentIDs READONLY 
AS 
BEGIN 
    SET NOCOUNT ON; 

    UPDATE s SET IsDeleted = 1 
    FROM dbo.Students AS s 
    INNER JOIN dbo.Class AS c 
    ON s.StudentId = c.StudentId 
    INNER JOIN dbo.ClassValueTable AS ct 
    ON c.PassId = ct.Id 
    WHERE ct.IsDeleted <> 1 
    AND EXISTS (SELECT 1 FROM @IDs WHERE StudentID = s.StudentID); 
END 
GO 

и код C# будет проходить в DataTable или, тем не менее, вы собрали коллекцию activeIds, а не список, разделенный запятыми.

DataTable dt = new DataTable(); 
dt.Columns.Add("ID", typeof(int)); 
dt.Rows.Add(1); 
dt.Rows.Add(2); 
dt.Rows.Add(3); 
dt.Rows.Add(4); 

... open connection etc. ... 

SqlCommand cmd = new SqlCommand("dbo.MarkStudentsAsDeleted", conn); 
cmd.CommandType = CommandType.StoredProcedure; 
SqlParameter tvp1 = cmd.Parameters.AddWithValue("@IDs", dt); 
tvp1.SqlDbType = SqlDbType.Structured; 
cmd.ExecuteNonQuery(); 

... close, dispose, etc. ... 

Если вы хотите, чтобы настаивать на переходе строку в хранимую процедуру, вы должны будете использовать разделенную функцию. Например:

CREATE FUNCTION dbo.SplitInts 
(
    @List  VARCHAR(MAX), 
    @Delimiter VARCHAR(255) = ',' 
) 
RETURNS TABLE 
WITH SCHEMABINDING 
AS 
    RETURN 
    ( 
    SELECT [value] = y.i.value('(./text())[1]', 'int') 
    FROM 
    ( 
     SELECT x = CONVERT(XML, '<i>' 
     + REPLACE(@List, @Delimiter, '</i><i>') 
     + '</i>').query('.') 
    ) AS a CROSS APPLY x.nodes('i') AS y(i) 
); 
GO 

Теперь хранимая процедура может быть:

CREATE PROCEDURE dbo.MarkStudentsAsDeleted 
    @IDs VARCHAR(MAX) 
AS 
BEGIN 
    SET NOCOUNT ON; 

    UPDATE s SET IsDeleted = 1 
    FROM dbo.Students AS s 
    INNER JOIN dbo.Class AS c 
    ON s.StudentId = c.StudentId 
    INNER JOIN dbo.ClassValueTable AS ct 
    ON c.PassId = ct.Id 
    WHERE ct.IsDeleted <> 1 
    AND EXISTS (SELECT 1 FROM dbo.SplitInts(@IDs, ',') WHERE Item = s.StudentID); 
END 
GO 
+0

На самом деле у меня уже есть активные идентификаторы в строке типа «1,2,3, ..». Вот почему я спрашивал, имеет ли смысл использовать параметры значения или просто передать его как строку в одном параметре? Извините за новый параметр этого значения. И большое спасибо за отличный пример! Действительно ценю это! – NoviceMe

+1

@NoviceMe Я получаю его, но где эта строка, разделенная запятыми *, поступает из *? Небо? В какой-то момент у вас должно быть * собрано * это каким-то образом ... –

+0

Я получаю список из папки и сохраняется в коде как IEnumerable, тогда я использую String.Join, чтобы сделать разделенный запятыми список. Надеюсь, я могу объяснить это сейчас? – NoviceMe

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