2013-04-16 3 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#으로하고 SQL 서버 2008

+0

[테이블 반환 매개 변수 (http://msdn.microsoft.com/en-us/library/bb675163.aspx) (그러나 C# 3이'SqlDbType.Structured'를 알고 있는지 모르겠다.) –

+0

@TimSchmelter - activeIds는 문자열이다. 그냥 문자열로 넘겨 줘? – NoviceMe

+1

테이블 반환 매개 변수를 사용하지 않고 사용하십시오. 왜 그것은 문자열이어야합니까? 어떤 시점에서 컬렉션에서 나오지 않습니까? 왜 그것을 문자열로 변환해야 비 문자열로 나눌 수 있습니까? 만약 당신이 그렇게하려고한다면, 지금 사용하고있는 SQL injection haven을 계속 사용하십시오 ... –

답변

3

예, 사용 테이블 반환 매개 변수를 사용하고 있습니다. A의 통과 것이다

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# 코드 :

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

이제 절차 (가입 나는 적절한에 중첩 된 IN 쿼리를 변경 한 주)를 사용할 수있다 : 첫째 유형을 만들 DataTable 또는 쉼표로 구분 된 목록이 아닌 activeId 컬렉션을 어셈블했습니다.

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, .."과 같은 문자열에 이미 activeIds가 있습니다. 그래서 왜 가치 매개 변수를 사용하거나 하나의 매개 변수에 문자열로 전달하는 것이 적합한 지 묻는 이유는 무엇입니까? 이 값 매개 변수에 대한 새로운 미안. 훌륭한 예를 들어 주셔서 감사합니다! 정말 감사합니다! – NoviceMe

+1

@NoviceMe 알 겠어.이 쉼표로 구분 된 문자열은 *에서 나온거야? 하늘? 당신은 어떤 점에서 어떤 식 으로든 * 조립 *해야합니다 ... –

+0

나는 폴더에서 목록을 얻고 IEnumerable로 코드에 저장됩니다. 그런 다음 String.Join을 사용하여 쉼표로 분리 된 목록을 만듭니다. 희망을 지금 설명 할 수 있을까요? – NoviceMe

관련 문제