Frage

Gibt es eine elegante Möglichkeit, die Übergabe einer Liste von IDs als Parameter an eine gespeicherte Prozedur zu handhaben?

Ich möchte beispielsweise, dass die Abteilungen 1, 2, 5, 7, 20 von meiner gespeicherten Prozedur zurückgegeben werden.In der Vergangenheit habe ich eine durch Kommas getrennte Liste von IDs übergeben, wie im folgenden Code, aber ich fühle mich dabei wirklich schmutzig.

SQL Server 2005 ist meiner Meinung nach meine einzige anwendbare Einschränkung.

create procedure getDepartments
  @DepartmentIds varchar(max)
as
  declare @Sql varchar(max)     
  select @Sql = 'select [Name] from Department where DepartmentId in (' + @DepartmentIds + ')'
  exec(@Sql)
War es hilfreich?

Lösung

Erland Sommarskog vertritt seit 16 Jahren die maßgebliche Antwort auf diese Frage: Arrays und Listen in SQL Server.

Es gibt mindestens ein Dutzend Möglichkeiten, ein Array oder eine Liste an eine Abfrage zu übergeben;jedes hat seine eigenen Vor- und Nachteile.

  • Tabellenwertige Parameter.Nur SQL Server 2008 und höher und wahrscheinlich einem universellen „besten“ Ansatz am nächsten.
  • Die iterative Methode.Übergeben Sie eine durch Trennzeichen getrennte Zeichenfolge und durchlaufen Sie eine Schleife.
  • Verwendung der CLR.Nur SQL Server 2005 und höher aus .NET-Sprachen.
  • XML.Sehr gut zum Einfügen vieler Zeilen;kann für SELECTs übertrieben sein.
  • Zahlentabelle.Höhere Leistung/Komplexität als einfache iterative Methode.
  • Elemente mit fester Länge.Die feste Länge verbessert die Geschwindigkeit gegenüber der durch Trennzeichen getrennten Zeichenfolge
  • Funktion der Zahlen.Variationen der Zahlentabelle und der Zahlentabelle mit fester Länge, bei denen die Zahlen in einer Funktion generiert werden und nicht aus einer Tabelle entnommen werden.
  • Rekursiver gemeinsamer Tabellenausdruck (CTE).SQL Server 2005 und höher, immer noch nicht zu komplex und leistungsfähiger als die iterative Methode.
  • Dynamisches SQL.Kann langsam sein und hat Auswirkungen auf die Sicherheit.
  • Übergeben der Liste als Viele Parameter.Mühsam und fehleranfällig, aber einfach.
  • Wirklich langsame Methoden.Methoden, die charindex, patindex oder LIKE verwenden.

Ich kann es wirklich nicht genug empfehlen lesen Sie den Artikel um mehr über die Kompromisse zwischen all diesen Optionen zu erfahren.

Andere Tipps

Ja, Ihre aktuelle Lösung ist anfällig für SQL-Injection-Angriffe.

Die beste Lösung, die ich gefunden habe, besteht darin, eine Funktion zu verwenden, die Text in Wörter aufteilt (einige davon sind hier veröffentlicht, oder Sie können sie verwenden). dieses hier aus meinem Blog) und verbinden Sie es dann mit Ihrem Tisch.Etwas wie:

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

Sie könnten XML verwenden.

Z.B.

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) 

Der Befehl sp_xml_preparedocument ist eingebaut.

Dies würde die Ausgabe erzeugen:

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

das alles (mehr?) von dem hat, was Sie brauchen.

Eine Methode, die Sie möglicherweise in Betracht ziehen sollten, wenn Sie häufig mit den Werten arbeiten, besteht darin, sie zunächst in eine temporäre Tabelle zu schreiben.Dann machen Sie einfach wie gewohnt mit.

Auf diese Weise analysieren Sie nur einmal.

Am einfachsten ist es, eines der „Split“-UDFs zu verwenden, aber so viele Leute haben Beispiele dafür gepostet, dass ich dachte, ich würde einen anderen Weg gehen ;)

In diesem Beispiel wird eine temporäre Tabelle erstellt, der Sie beitreten können (#tmpDept), und diese mit den von Ihnen übergebenen Abteilungs-IDs füllen.Ich gehe davon aus, dass Sie sie durch Kommas trennen, aber Sie können es natürlich beliebig ändern.

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

Dadurch können Sie eine Abteilungs-ID, mehrere IDs mit Kommas dazwischen oder sogar mehrere IDs mit Kommas und Leerzeichen dazwischen übergeben.

Wenn Sie also etwas getan haben wie:

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

Sie würden die Namen aller Abteilungs-IDs sehen, die Sie eingegeben haben ...

Auch dies kann vereinfacht werden, indem eine Funktion zum Auffüllen der temporären Tabelle verwendet wird ...Ich habe es hauptsächlich ohne gemacht, nur um etwas Langeweile zu vertreiben :-P

– Kevin Fairchild

Eine superschnelle XML-Methode, wenn Sie eine gespeicherte Prozedur verwenden und die durch Kommas getrennte Liste der Abteilungs-IDs übergeben möchten:

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))

Alle Ehre gebührt Guru Brad Schulzs Blog

Probier diese:

@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)  +'%')

sehr einfach.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top