Translate: 
EnglishFrenchGermanItalianPolishPortugueseRussianSpanish

Odpowiednik PHP’owej funkcji explode() dla Microsoft SQL Server 2000/2005

W życiu każdego programisty istnieje czasami potrzeba przeniesienia funkcjonalności z jednego języka programowania do drugiego.

Tym razem konieczność sprawiła że musiałem zmigrować PHP’ową funkcję explode() do jej proceduralnego odpowiednika w bazie Microsoft SQL Server.

Oto owoc mojej jednodniowej walki:

SET ANSI_NULLS ON
SET QUOTED_IDENTIFIER ON
GO
 
CREATE PROCEDURE [dbo].[AGR_EXPLODE]
	@INPUT NVARCHAR(MAX),
	@SEPARATOR NVARCHAR(100) = '	'
AS
BEGIN
	SET NOCOUNT ON
	DECLARE @LAST_POSITION BIGINT
	DECLARE @CURRENT_POSITION BIGINT
	DECLARE @CURRENT_VALUE NVARCHAR(MAX)
	DECLARE @SEPARATOR_LENGTH INT
	DECLARE @INPUT_LENGTH BIGINT
	DECLARE @START BIGINT
	DECLARE @ID BIGINT
 
	DECLARE @OUTPUT TABLE (
		ID BIGINT NOT NULL PRIMARY KEY,
		MYVALUE NVARCHAR(MAX) NOT NULL
	)
 
	SET @SEPARATOR_LENGTH = LEN(@SEPARATOR)
	SET @INPUT_LENGTH = LEN(@INPUT)
	SET @LAST_POSITION = -@SEPARATOR_LENGTH;
	SET @ID = 1
	SET @CURRENT_POSITION = CHARINDEX(@SEPARATOR, @INPUT);
	WHILE (@CURRENT_POSITION > 0) 
	BEGIN
		INSERT INTO @OUTPUT VALUES(@ID, (SUBSTRING(@INPUT, @LAST_POSITION + @SEPARATOR_LENGTH, @CURRENT_POSITION - @LAST_POSITION - @SEPARATOR_LENGTH)))
		SET @LAST_POSITION = @CURRENT_POSITION;
		SET @CURRENT_POSITION = CHARINDEX(@SEPARATOR, @INPUT, @LAST_POSITION + 1);
		SET @ID = @ID + 1
	END
 
	IF(@INPUT_LENGTH > @LAST_POSITION)
	BEGIN
		INSERT INTO @OUTPUT VALUES(@ID, (SUBSTRING(@INPUT, @LAST_POSITION + @SEPARATOR_LENGTH, @INPUT_LENGTH - @LAST_POSITION)))	
	END
	SELECT * FROM @OUTPUT
	RETURN 0
END

Przykładowe użycie

Treść zapytania:

EXEC agr_explode "ala ma!!!@kota", "!!!@"

Oraz odpowiedzi:

ID                   MYVALUE
---------------------------------
1                    ala ma
2                    kota

Uwagi końcowe

Największym problemem jest to, że Microsoft nie lubi zbyt długich stringów z danymi. W wersji SQL Server 2000 typ zmiennej VARCHAR(MAX) mógł osiągać długość maksymalnie około 8000 znaków, co na dzisiejsze standardy jest śmiesznie małą wartością.

Także większość procedur operujących na ciągach danych nie potrafi sobie radzić ze zbyt długim tekstem. W przypadku powyższego kodu nie powinno być z tym jednak problemu (choć odradzam używania aż tak starych wersji serwera SQL).

Ponadto z testów wydajnościowych tej procedury wynika, że T-SQL nie jest dobrym rozwiązaniem do zastąpienia funkcji explode().

O ile różnica wydajności przy kliku tysiącach wyrazów nie jest problemem, to jednak o wiele lepiej (szybciej) żądany efekt można osiągnąć rozbijając dane wejściowe jeszcze po stronie aplikacji napisanej w języku C#/C++/PHP.

Programista jednak nie zawsze ma taką możliwość…

Tagi: , , ,

Dodaj odpowiedź