복붙노트

[SQL] 목록 <>에 대한 SQL 저장 프로 시저를 전달

SQL

목록 <>에 대한 SQL 저장 프로 시저를 전달

나는 종종 데이터베이스의 특정 레코드에 여러 항목을로드 했어. 예를 들어 웹 페이지가 표시 항목은 데이터베이스의 레코드 (보고서는 보고서 테이블의 레코드이며, 항목은 항목 테이블의 레코드입니다)이 모두있는 단일 보고서에 포함합니다. 사용자는 웹 응용 프로그램을 통해 하나의 보고서에 포함하고의 그들이 3 개 항목을 선택하고 제출 말할 수 있도록 항목을 선택합니다. 이 과정은 테이블이라고 ReportItems (ReportId, 항목 Id)에 레코드를 추가하여이 보고서에이 3 개 항목을 추가합니다.

현재, 나는 코드에 이런 짓을 할 것이다 :

public void AddItemsToReport(string connStr, int Id, List<int> itemList)
{
    Database db = DatabaseFactory.CreateDatabase(connStr);

    string sqlCommand = "AddItemsToReport"
    DbCommand dbCommand = db.GetStoredProcCommand(sqlCommand);

    string items = "";
    foreach (int i in itemList)
        items += string.Format("{0}~", i);

    if (items.Length > 0)
        items = items.Substring(0, items.Length - 1);

    // Add parameters
    db.AddInParameter(dbCommand, "ReportId", DbType.Int32, Id);
    db.AddInParameter(dbCommand, "Items", DbType.String, perms);
    db.ExecuteNonQuery(dbCommand);
}

과 저장 프로 시저에서이 :

INSERT INTO ReportItem (ReportId,ItemId)
SELECT  @ReportId,
          Id
FROM     fn_GetIntTableFromList(@Items,'~')

어디 함수가 정수의 1 열 테이블을 반환합니다.

이런 일을 처리하는 더 좋은 방법이 : 제 질문은 이것이다? 참고, 내가 그와 같은 데이터베이스 정상화 또는 아무것도 요구하고 있지 않다, 내 질문은 코드와 특별히 관련이 있습니다.

해결법

  1. ==============================

    1.SQL Server 2008로가는 당신을위한 옵션 인 경우이 정확한 문제를 해결하기 위해 "테이블 반환 매개 변수"라는 새로운 기능이있다.

    SQL Server 2008로가는 당신을위한 옵션 인 경우이 정확한 문제를 해결하기 위해 "테이블 반환 매개 변수"라는 새로운 기능이있다.

    여기와 여기에 TVP에 대한 자세한 내용을 확인하거나 "SQL Server 2008의 테이블 반환 매개 변수"를 구글에게 물어 - 당신은 정보와 샘플을 많이 찾을 수 있습니다.

    추천 - 당신은 SQL Server 2008로 이동할 수 있다면 ...

  2. ==============================

    2.귀하의 문자열에 가입 로직은 아마 단순화 할 수있다 :

    귀하의 문자열에 가입 로직은 아마 단순화 할 수있다 :

    string items = 
        string.Join("~", itemList.Select(item=>item.ToString()).ToArray());
    

    그것은 당신에게 닷넷에서 비싼 일부 문자열 연결을 저장합니다.

    난 아무것도 당신이 항목을 저장하는 방식에 문제가 생각하지 않습니다. 당신은 좋은 것입니다 데시벨로 여행을 제한하고 있습니다. 데이터 구조가 INT의 목록보다 더 복잡 경우에, 나는 XML을 건의 할 것입니다.

    참고 :이 우리에게 어떤 문자열 연결을 절약 할 수 있다면 (이것은 indeeed 않음) 코멘트에 요청했다. 나는 그것이 훌륭한 질문과 그 후속 싶은 생각합니다.

    당신은 리플렉터와 개방 string.Join을 벗겨 경우에 당신은 마이크로 소프트 (단어의 닷넷 의미에서) 숯불 포인터와 UnSafeCharBuffer라는 구조를 사용하여 포함하여 기술을 안전하지 않은 몇 가지를 사용하는 것을 볼 수 있습니다. 그들이 무엇을 당신이 정말로 그것을 아래로 비등 할 때, 빈 문자열을 가로 질러 걸어 조인 구축 포인터를 사용하고 있습니다. 주요 이유 문자열 연결 닷넷 너무 비싼 것을 기억하는 것은 문자열이 불변이기 때문에 새로운 문자열 객체가 모든 연결을위한 힙에 배치되어 있다는 점이다. 그 메모리 작업이 비싸다. String.Join (...)는 기본적으로 다음의 포인터로 동작시, 일단 메모리를 할당한다. 매우 빠른.

  3. ==============================

    3.당신의 기술을 가진 하나의 잠재적 인 문제는 매우 큰 목록을 처리하지 않는다는 것입니다 - 당신은 당신의 데이터베이스에 대한 최대 문자열 길이를 초과 할 수 있습니다. I는 헬퍼 메소드를 사용하는 (또한 다음 실시 임의로 확인하고 중복 제거합니다 IDS) 이하 지정된 최대보다 각각의 스트링의리스트에 연접 정수 값 :

    당신의 기술을 가진 하나의 잠재적 인 문제는 매우 큰 목록을 처리하지 않는다는 것입니다 - 당신은 당신의 데이터베이스에 대한 최대 문자열 길이를 초과 할 수 있습니다. I는 헬퍼 메소드를 사용하는 (또한 다음 실시 임의로 확인하고 중복 제거합니다 IDS) 이하 지정된 최대보다 각각의 스트링의리스트에 연접 정수 값 :

    public static IEnumerable<string> ConcatenateValues(IEnumerable<int> values, string separator, int maxLength, bool skipDuplicates)
    {
        IDictionary<int, string> valueDictionary = null;
        StringBuilder sb = new StringBuilder();
        if (skipDuplicates)
        {
            valueDictionary = new Dictionary<int, string>();
        }
        foreach (int value in values)
        {
            if (skipDuplicates)
            {
                if (valueDictionary.ContainsKey(value)) continue;
                valueDictionary.Add(value, "");
            }
            string s = value.ToString(CultureInfo.InvariantCulture);
            if ((sb.Length + separator.Length + s.Length) > maxLength)
            {
                // Max length reached, yield the result and start again
                if (sb.Length > 0) yield return sb.ToString();
                sb.Length = 0;
            }
            if (sb.Length > 0) sb.Append(separator);
            sb.Append(s);
        }
        // Yield whatever's left over
        if (sb.Length > 0) yield return sb.ToString();
    }
    

    그럼 당신은 그에게 같은 것을 사용 :

    using(SqlCommand command = ...)
    {
        command.Connection = ...;
        command.Transaction = ...; // if in a transaction
        SqlParameter parameter = command.Parameters.Add("@Items", ...);
        foreach(string itemList in ConcatenateValues(values, "~", 8000, false))
        {
            parameter.Value = itemList;
            command.ExecuteNonQuery();
        }
    }
    
  4. ==============================

    4.당신도 당신이 이미 가지고 무엇을, 구분 된 문자열을 전달하고 테이블 값을 구문 분석, 또는 다른 선택의 여지가 XML의 wodge에 전달하고 좀 많이 동일합니다을 수행합니다

    당신도 당신이 이미 가지고 무엇을, 구분 된 문자열을 전달하고 테이블 값을 구문 분석, 또는 다른 선택의 여지가 XML의 wodge에 전달하고 좀 많이 동일합니다을 수행합니다

    http://weblogs.asp.net/jgalloway/archive/2007/02/16/passing-lists-to-sql-server-2005-with-xml-parameters.aspx

    나는 그들이 일의이 유형을 처리 할 수있는 새로운 기능을 추가 한 경우 아직보고 SQL 2008에서 볼 수있는 기회가 없었어요.

  5. ==============================

    5.왜 테이블 반환 매개 변수를 사용하지? https://docs.microsoft.com/en-us/dotnet/framework/data/adonet/sql/table-valued-parameters

    왜 테이블 반환 매개 변수를 사용하지? https://docs.microsoft.com/en-us/dotnet/framework/data/adonet/sql/table-valued-parameters

  6. ==============================

    6.이 문제에 대한 자세한 설명하고 사용할 수있는 다른 방법에 대한 http://www.sommarskog.se/arrays-in-sql-2005.html를 참조하십시오.

    이 문제에 대한 자세한 설명하고 사용할 수있는 다른 방법에 대한 http://www.sommarskog.se/arrays-in-sql-2005.html를 참조하십시오.

  7. ==============================

    7.테이블 반환 매개 변수 : 여기 sqlteam.com에서 매개 변수 값을 갖는 테이블에 매우 명확한 설명입니다

    테이블 반환 매개 변수 : 여기 sqlteam.com에서 매개 변수 값을 갖는 테이블에 매우 명확한 설명입니다

  8. ==============================

    8.저장 프로 시저에서 여러 값에 대한 단일 필드 쿼리 http://www.norimek.com/blog/post/2008/04/Query-a-Single-Field-for-Multiple-Values-in-a-Stored-Procedure.aspx

    저장 프로 시저에서 여러 값에 대한 단일 필드 쿼리 http://www.norimek.com/blog/post/2008/04/Query-a-Single-Field-for-Multiple-Values-in-a-Stored-Procedure.aspx

  9. from https://stackoverflow.com/questions/209686/passing-list-to-sql-stored-procedure by cc-by-sa and MIT license