سؤال

هل هناك طريقة رائعة للتعامل مع تمرير قائمة المعرفات كمعلمة لإجراء مخزن؟

على سبيل المثال، أريد إرجاع الأقسام 1، 2، 5، 7، 20 بواسطة الإجراء المخزن الخاص بي.في الماضي، قمت بتمرير قائمة معرفات مفصولة بفواصل، مثل الكود أدناه، لكنني أشعر بالقذارة حقًا عند القيام بذلك.

أعتقد أن SQL Server 2005 هو القيد الوحيد القابل للتطبيق.

create procedure getDepartments
  @DepartmentIds varchar(max)
as
  declare @Sql varchar(max)     
  select @Sql = 'select [Name] from Department where DepartmentId in (' + @DepartmentIds + ')'
  exec(@Sql)
هل كانت مفيدة؟

المحلول

لقد حافظ إرلاند سومارسكوغ على الإجابة الموثوقة على هذا السؤال طوال الستة عشر عامًا الماضية: المصفوفات والقوائم في SQL Server.

هناك ما لا يقل عن اثنتي عشرة طريقة لتمرير مصفوفة أو قائمة إلى استعلام؛لكل منها إيجابيات وسلبيات فريدة من نوعها.

أنا حقا لا أستطيع أن أوصي بما فيه الكفاية اقرأ المقال للتعرف على المفاضلات بين كل هذه الخيارات.

نصائح أخرى

نعم، الحل الحالي الخاص بك عرضة لهجمات حقن SQL.

أفضل حل وجدته هو استخدام وظيفة تقسم النص إلى كلمات (هناك عدد قليل منشور هنا، أو يمكنك استخدام هذا واحد من مدونتي) ثم قم بضم ذلك إلى طاولتك.شيء مثل:

SELECT d.[Name]
FROM Department d
    JOIN dbo.SplitWords(@DepartmentIds) w ON w.Value = d.DepartmentId

يمكنك استخدام XML.

على سبيل المثال

declare @xmlstring as  varchar(100) 
set @xmlstring = '<args><arg value="42" /><arg2>-1</arg2></args>' 

declare @docid int 

exec sp_xml_preparedocument @docid output, @xmlstring

select  [id],parentid,nodetype,localname,[text]
from    openxml(@docid, '/args', 1) 

الامر sp_xml_preparedocument بنيت في.

وهذا من شأنه أن ينتج الإخراج:

id  parentid    nodetype    localname   text
0   NULL        1           args        NULL
2   0           1           arg         NULL
3   2           2           value       NULL
5   3           3           #text       42
4   0           1           arg2        NULL
6   4           3           #text       -1

الذي يحتوي على كل (المزيد؟) ما تحتاجه.

إحدى الطرق التي قد ترغب في أخذها في الاعتبار إذا كنت ستعمل مع القيم كثيرًا هي كتابتها في جدول مؤقت أولاً.ثم تنضم إليها كالمعتاد.

بهذه الطريقة، أنت تقوم بالتحليل مرة واحدة فقط.

من الأسهل استخدام أحد UDFs "المقسمة"، لكن الكثير من الأشخاص قد نشروا أمثلة على ذلك، ففكرت في أنني سأسلك طريقًا مختلفًا؛)

سيقوم هذا المثال بإنشاء جدول مؤقت لتتمكن من الانضمام إليه (#tmpDept) وتعبئته بمعرف القسم الذي قمت بتمريره.أفترض أنك تفصل بينها بفواصل، ولكن يمكنك - بالطبع - تغييرها إلى ما تريد.

IF OBJECT_ID('tempdb..#tmpDept', 'U') IS NOT NULL
BEGIN
    DROP TABLE #tmpDept
END

SET @DepartmentIDs=REPLACE(@DepartmentIDs,' ','')

CREATE TABLE #tmpDept (DeptID INT)
DECLARE @DeptID INT
IF IsNumeric(@DepartmentIDs)=1
BEGIN
    SET @DeptID=@DepartmentIDs
    INSERT INTO #tmpDept (DeptID) SELECT @DeptID
END
ELSE
BEGIN
        WHILE CHARINDEX(',',@DepartmentIDs)>0
        BEGIN
            SET @DeptID=LEFT(@DepartmentIDs,CHARINDEX(',',@DepartmentIDs)-1)
            SET @DepartmentIDs=RIGHT(@DepartmentIDs,LEN(@DepartmentIDs)-CHARINDEX(',',@DepartmentIDs))
            INSERT INTO #tmpDept (DeptID) SELECT @DeptID
        END
END

سيسمح لك هذا بتمرير معرف قسم واحد، أو معرفات متعددة بفواصل بينها، أو حتى معرفات متعددة بفواصل ومسافات بينها.

لذلك إذا فعلت شيئًا مثل:

SELECT Dept.Name 
FROM Departments 
JOIN #tmpDept ON Departments.DepartmentID=#tmpDept.DeptID
ORDER BY Dept.Name

ستشاهد أسماء جميع معرفات الأقسام التي مررت بها...

مرة أخرى، يمكن تبسيط ذلك باستخدام دالة لملء الجدول المؤقت...لقد فعلت ذلك بشكل أساسي بدون أحد فقط لقتل بعض الملل :-P

-- كيفن فيرتشايلد

طريقة XML فائقة السرعة، إذا كنت تريد استخدام إجراء مخزن وتمرير قائمة معرفات الأقسام المفصولة بفواصل:

Declare @XMLList xml
SET @XMLList=cast('<i>'+replace(@DepartmentIDs,',','</i><i>')+'</i>' as xml)
SELECT x.i.value('.','varchar(5)') from @XMLList.nodes('i') x(i))

كل الفضل يذهب إلى جورو مدونة براد شولز

جرب هذه:

@list_of_params varchar(20) -- value 1, 2, 5, 7, 20 

SELECT d.[Name]
FROM Department d
where @list_of_params like ('%'+ CONVERT(VARCHAR(10),d.Id)  +'%')

بسيط جدا.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top