Jeżeli robimy dużo zmian w tekście używając funkcji REPLACE dochodzimy do momentu w którym edycja jest możliwa wyłącznie przy odpowiednim formatowaniu kodu.
Przykładem jest funkcja konwertująca stronę kodową Mazovia (CP620) a stroną Windows-1250 napisaną przez Pawła Potasińskiego.
CREATE FUNCTION dbo.ufn_MazoviaTo1250 (@String varchar(maX))
RETURNS varchar(max)
WITH SCHEMABINDING
AS
BEGIN
SET @String = @String COLLATE Polish_BIN;
RETURN
REPLACE (
REPLACE (
REPLACE (
REPLACE (
REPLACE (
REPLACE (
REPLACE (
REPLACE (
REPLACE (
REPLACE (
REPLACE (
REPLACE (
REPLACE (
REPLACE (
REPLACE (
REPLACE (
REPLACE (
REPLACE (
@String, CHAR(165), CHAR(209) -- Ñ
), CHAR(143), CHAR(165) -- ¥
), CHAR(163), CHAR(211) -- Ó
), CHAR(156), CHAR(163) -- £
), CHAR(149), CHAR(198) -- Æ
), CHAR(144), CHAR(202) -- Ê
), CHAR(152), CHAR(140) -- Œ
), CHAR(160), CHAR(143) --
), CHAR(161), CHAR(175) -- ¯
), CHAR(134), CHAR(185) -- ¹
), CHAR(141), CHAR(230) -- æ
), CHAR(145), CHAR(234) -- ê
), CHAR(146), CHAR(179) -- ³
), CHAR(164), CHAR(241) -- ñ
), CHAR(162), CHAR(243) -- ó
), CHAR(158), CHAR(156) -- œ
), CHAR(166), CHAR(159) -- Ÿ
), CHAR(167), CHAR(191) -- ¿
) COLLATE database_default;
END;
Wygląda nieźle ale jakby trzeba było zamienić więcej niż 100 znaków?
Można zrobić coś takiego, żeby było łatwiej tworzymy tabelę mapowania
CREATE TABLE mapa (id INT IDENTITY(1,1), map VARCHAR(256), rep NVARCHAR(256))
go
Dodajemy do niej wartości kodu ascii
INSERT mapa (map,rep)
VALUES (165,209)
, (143 , 165)
, (163 , 211)
, (156 , 163)
, (149 , 198)
, (144 , 202)
, (152 , 140)
, (160 , 143)
, (161 , 175)
, (134 , 185)
, (141 , 230)
, (145 , 234)
, (146 , 179)
, (164 , 241)
, (162 , 243)
, (158 , 156)
, (166 , 159)
, (167 , 191)
go
I robimy funkcję
create function dbo.translate(@txt nvarchar(max))
returns nvarchar(max)
as
begin
SET @txt =@txt COLLATE Polish_BIN
select @txt = replace(@txt, CHAR(map), CHAR(rep))
from mapa
return @txt;
end
go
metody tej możemy użyc również do zamieniania dowolnych ciągów znakowych w tekście, należy zmodyfikować funkcję
alter function dbo.translate(@txt nvarchar(max))
returns nvarchar(max)
as
begin
select @txt = replace(@txt, map, rep)
from mapa
return @txt
end
go
zmieniamy dane do mapowania
DELETE FROM mapa
go
INSERT mapa (map,rep)
VALUES (1,'jeden*')
, (2 , 'dwa*')
, (3 , 'trzy*')
, (4 , 'cztery*')
, (5, 'pięć*')
, (6 , 'sześć*')
, (7 , 'siedem*')
, (8 , 'osiem*')
, (9 , 'dziewięć*')
, (0 , 'zero*')
go
testujemy
SELECT dbo.translate ('167870349076');
Jakiekolwiek dywagacje na temat udoskonalania funkcji T-SQLa z "REPLACE" nie mają sensu. Są za wolne!
OdpowiedzUsuńJedyne słuszne rozwiązanie to funkcja CLR.
Tylko bez żadnych regexp-ów.
Same REPLACE - sprawdzone i przetestowane.
Taka CLR-owa funkcja działa 10 razy szybciej.
Polecam.
pozdr
GREGOR
mam pewne obawy czy uda się napisać CLR który będzie szybszy przy próbce wynoszącej 10 - 20 obiektów. CLR dużo dłużej się inicjują i żeby pokazały swoje możliwości próbka musi mieć parę set rekordów.
OdpowiedzUsuń@GREGOR: Samo Replace nie daje chyba wyboru co do rozróżniania wielkich i małych liter (co na pewno umożliwiają RegExpy). A REPLACE w T-SQL działa z uwzględnieniem collation.
OdpowiedzUsuń