Sqlserver
 sql >> Datenbank >  >> RDS >> Sqlserver

Eine Variable in eine IN-Klausel innerhalb einer SQL-Funktion übergeben?

Hier ist ein etwas effizienterer Weg, um eine Liste von ganzen Zahlen aufzuteilen. Erstellen Sie zunächst eine Zahlentabelle, falls Sie noch keine haben. Dadurch wird eine Tabelle mit 100.000 eindeutigen Ganzzahlen erstellt (möglicherweise benötigen Sie mehr oder weniger):

;WITH x AS
(
   SELECT TOP (1000000) Number = ROW_NUMBER() OVER 
   (ORDER BY s1.[object_id])
   FROM sys.all_objects AS s1 CROSS JOIN sys.all_objects AS s2
   ORDER BY s1.[object_id]
)
SELECT Number INTO dbo.Numbers FROM x;

CREATE UNIQUE CLUSTERED INDEX n ON dbo.Numbers(Number);

Dann eine Funktion:

CREATE FUNCTION [dbo].[SplitInts_Numbers]
(
   @List       NVARCHAR(MAX),
   @Delimiter  NVARCHAR(255)
)
RETURNS TABLE
WITH SCHEMABINDING
AS
   RETURN
   (
       SELECT Item = CONVERT(INT, SUBSTRING(@List, Number,
         CHARINDEX(@Delimiter, @List + @Delimiter, Number) - Number))
       FROM dbo.Numbers
       WHERE Number <= CONVERT(INT, LEN(@List))
         AND SUBSTRING(@Delimiter + @List, Number, 1) = @Delimiter
   );

Hier können Sie die Leistung mit einem iterativen Ansatz vergleichen:

http://sqlfiddle.com/#!3/960d2/1

Um die Zahlentabelle zu vermeiden, können Sie auch eine XML-basierte Version der Funktion ausprobieren - sie ist kompakter, aber weniger effizient:

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

Wie auch immer, sobald Sie eine Funktion haben, können Sie einfach sagen:

WHERE ID IN (SELECT Item FROM dbo.SplitInts_Numbers(@MyList, ','));