SELECT REPLACE('<strong>100</strong><b>.00 GB', '%^(^-?\d*\.{0,1}\d+$)%', '');
数値の2つの部分の間のマークアップを上記の正規表現に置き換えたいのですが、うまくいかないようです。 '%[^0-9]%'
のような単純なものをテストするためだけに試したが、どちらも機能しなかったため、正規表現の構文が間違っているかどうかはわかりません。誰も私がこれを達成する方法を知っていますか?
PATINDEX を使用して、パターン(文字列)の最初のインデックスを検索できます。次に、 STUFF を使用して、一致したpattern(string)に別の文字列を挿入します。
各行をループします。不正な文字をそれぞれ希望の文字に置き換えます。あなたの場合、非数値を空白に置き換えてください。内側のループは、ループの現在のセルに複数の不正な文字がある場合です。
DECLARE @counter int
SET @counter = 0
WHILE(@counter < (SELECT MAX(ID_COLUMN) FROM Table))
BEGIN
WHILE 1 = 1
BEGIN
DECLARE @RetVal varchar(50)
SET @RetVal = (SELECT Column = STUFF(Column, PATINDEX('%[^0-9.]%', Column),1, '')
FROM Table
WHERE ID_COLUMN = @counter)
IF(@RetVal IS NOT NULL)
UPDATE Table SET
Column = @RetVal
WHERE ID_COLUMN = @counter
ELSE
break
END
SET @counter = @counter + 1
END
注意:ただし、これは遅いです! varchar列があると影響があります。そのため、LTRIM RTRIMを使用すると少し役立つ場合があります。とにかく、遅いです。
クレジットは this StackOverFlowの答えになります。
EDITクレジットは@srutzkyにも送られます
編集(by Tmdean)一度に1行ずつ実行する代わりに、この回答をよりセットベースのソリューションに適合させることができます。それでも、1行の非数値文字の最大数を反復処理するため、理想的ではありませんが、ほとんどの状況で許容できると思います。
WHILE 1 = 1 BEGIN
WITH q AS
(SELECT ID_Column, PATINDEX('%[^0-9.]%', Column) AS n
FROM Table)
UPDATE Table
SET Column = STUFF(Column, q.n, 1, '')
FROM q
WHERE Table.ID_Column = q.ID_Column AND q.n != 0;
IF @@ROWCOUNT = 0 BREAK;
END;
フィールドがまだスクラブされているかどうかを示すビット列をテーブルに保持すると、効率を大幅に向上させることもできます。 (私の例ではNULLは「不明」を表し、列のデフォルトである必要があります。)
DECLARE @done bit = 0;
WHILE @done = 0 BEGIN
WITH q AS
(SELECT ID_Column, PATINDEX('%[^0-9.]%', Column) AS n
FROM Table
WHERE COALESCE(Scrubbed_Column, 0) = 0)
UPDATE Table
SET Column = STUFF(Column, q.n, 1, ''),
Scrubbed_Column = 0
FROM q
WHERE Table.ID_Column = q.ID_Column AND q.n != 0;
IF @@ROWCOUNT = 0 SET @done = 1;
-- if Scrubbed_Column is still NULL, then the PATINDEX
-- must have given 0
UPDATE table
SET Scrubbed_Column = CASE
WHEN Scrubbed_Column IS NULL THEN 1
ELSE NULLIF(Scrubbed_Column, 0)
END;
END;
スキーマを変更したくない場合は、中間値をテーブル値変数に保存し、最後に実際のテーブルに適用するように簡単に調整できます。
一般的な意味で、SQL Serverは正規表現をサポートしていないため、ネイティブT-SQLコードで使用できません。
それを行うCLR関数を作成できます。たとえば、 here を参照してください。
見つかった文字をその単独の位置で取り除く代わりに、Replace(Column, BadFoundCharacter, '')
を使用すると、かなり速くなります。さらに、各列で次に見つかった1つの不良文字を単に置き換えるのではなく、見つかったすべての文字を置き換えます。
WHILE 1 = 1 BEGIN
UPDATE dbo.YourTable
SET Column = Replace(Column, Substring(Column, PatIndex('%[^0-9.-]%', Column), 1), '')
WHERE Column LIKE '%[^0-9.-]%'
If @@RowCount = 0 BREAK;
END;
操作が少ないためだけに、これは受け入れられた答えよりもうまくいくと確信しています。他にももっと高速な方法がありますが、今はそれらを探索する時間はありません。
私は他の何かを探してこの投稿に出くわしましたが、はるかに効率的であり、実際にはセットベースのクエリで使用する場合はすべての関数のデフォルト実装であるソリューションを言及すると思いましたテーブル関数。トピックはまだアクティブなようですので、うまくいけば、これは誰かに役立つでしょう。
ランダムなnewidから文字を削除する1m行のテストセットに基づく再帰セットベースのクエリまたはスカラー関数の実行に基づくこれまでのいくつかの回答のランタイムの例は、WHILEループの例では34sから2m05s、1m3sから{関数の例についてはforever}。
クロスアプライでテーブル関数を使用すると、10sで同じ目標が達成されます。最大長など、ニーズに合わせて調整する必要がある場合があります。
関数:
CREATE FUNCTION [dbo].[RemoveChars](@InputUnit VARCHAR(40))
RETURNS TABLE
AS
RETURN
(
WITH Numbers_prep(Number) AS
(
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
)
,Numbers(Number) AS
(
SELECT TOP (ISNULL(LEN(@InputUnit),0))
row_number() OVER (ORDER BY (SELECT NULL))
FROM Numbers_prep a
CROSS JOIN Numbers_prep b
)
SELECT
OutputUnit
FROM
(
SELECT
substring(@InputUnit,Number,1)
FROM Numbers
WHERE substring(@InputUnit,Number,1) like '%[0-9]%'
ORDER BY Number
FOR XML PATH('')
) Sub(OutputUnit)
)
使用法:
UPDATE t
SET column = o.OutputUnit
FROM ##t t
CROSS APPLY [dbo].[RemoveChars](t.column) o
これは、以前の回答に基づいてこれを達成するために作成した関数です。
CREATE FUNCTION dbo.RepetitiveReplace
(
@P_String VARCHAR(MAX),
@P_Pattern VARCHAR(MAX),
@P_ReplaceString VARCHAR(MAX),
@P_ReplaceLength INT = 1
)
RETURNS VARCHAR(MAX)
BEGIN
DECLARE @Index INT;
-- Get starting point of pattern
SET @Index = PATINDEX(@P_Pattern, @P_String);
while @Index > 0
begin
--replace matching charactger at index
SET @P_String = STUFF(@P_String, PATINDEX(@P_Pattern, @P_String), @P_ReplaceLength, @P_ReplaceString);
SET @Index = PATINDEX(@P_Pattern, @P_String);
end
RETURN @P_String;
END;
もともと私は、SQLサーバーでうまく機能しない再帰関数を持っていました.32のネストレベルの制限があるため、関数で32回以上の置換をしようとすると、次のようなエラーが発生します。サーバーレベルを変更してネストを許可する(これは、ループが終了しないように危険な場合がある)のではなく、Whileループに切り替える方が理にかなっています。
最大のストアドプロシージャ、関数、トリガー、またはビューのネストレベルを超えています(制限32)。
ソリューションをSQL関数内にラップすると、再利用したい場合に便利です。私は細胞レベルでそれをしているので、これを別の答えとして入れています:
CREATE FUNCTION [dbo].[fnReplaceInvalidChars] (@string VARCHAR(300))
RETURNS VARCHAR(300)
BEGIN
DECLARE @str VARCHAR(300) = @string;
DECLARE @Pattern VARCHAR (20) = '%[^a-zA-Z0-9]%';
DECLARE @Len INT;
SELECT @Len = LEN(@String);
WHILE @Len > 0
BEGIN
SET @Len = @Len - 1;
IF (PATINDEX(@Pattern,@str) > 0)
BEGIN
SELECT @str = STUFF(@str, PATINDEX(@Pattern,@str),1,'');
END
ELSE
BEGIN
BREAK;
END
END
RETURN @str
END
ストアドプロシージャに入るパラメータに対してのみこれを行う場合は、次を使用できます。
while PatIndex('%[^0-9]%', @Param) > 0
select @Param = Replace(@Param, Substring(@Param, PatIndex('%[^0-9]%', @Param), 1), '')
私は、アルファベットの各文字を反復するのがより簡単で速いアプローチだと思います:
DECLARE @i int
SET @i = 0
WHILE(@i < 256)
BEGIN
IF char(@i) NOT IN ('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.')
UPDATE Table SET Column = replace(Column, char(@i), '')
SET @i = @i + 1
END
時間フィールドに数字以外の文字を含む文字列をクリーンアップするために、この関数を作成しました。この時間には、20:??のような議事録を追加しなかったときに疑問符が含まれていました。関数は各文字をループし、?を置き換えます0で:
CREATE FUNCTION [dbo].[CleanTime]
(
-- Add the parameters for the function here
@intime nvarchar(10)
)
RETURNS nvarchar(5)
AS
BEGIN
-- Declare the return variable here
DECLARE @ResultVar nvarchar(5)
DECLARE @char char(1)
-- Add the T-SQL statements to compute the return value here
DECLARE @i int = 1
WHILE @i <= LEN(@intime)
BEGIN
SELECT @char = CASE WHEN substring(@intime,@i,1) like '%[0-9:]%' THEN substring(@intime,@i,1) ELSE '0' END
SELECT @ResultVar = concat(@ResultVar,@char)
set @i = @i + 1
END;
-- Return the result of the function
RETURN @ResultVar
END