SQLを使用して文字列の最後の出現のインデックスを見つける簡単な方法はありますか?現在、SQL Server 2000を使用しています。基本的に、.NET System.String.LastIndexOf
メソッドが提供する機能が必要です。少しグーグルでこれが明らかになりました- 最後のインデックスを取得する関数 -しかし、「テキスト」列式を渡した場合は機能しません。他のソリューションは、検索するテキストが1文字の長さである場合にのみ機能します。
おそらく関数を作成する必要があります。もしそうするなら、ここに投稿して、皆さんがそれを見て、おそらく利用できるようにします。
テキストデータ型の場合、 関数の小さなリスト に制限されます。
私が提案できるのは、PATINDEX
で始まることですが、結果が得られるか、ゼロになるまでDATALENGTH-1, DATALENGTH-2, DATALENGTH-3
などから逆方向に動作します(DATALENGTH-DATALENGTH)
これは本当にSQL Server 2000
が単に処理できないものです。
他の回答の編集:REVERSEは、SQL Server 2000のテキストデータで使用できる関数のリストに含まれていません
簡単な方法ですか?いいえ、しかし、私は逆を使用しました。文字通り。
以前のルーチンでは、指定された文字列の最後の出現を見つけるために、REVERSE()関数を使用し、CHARINDEXを使用し、その後再びREVERSEを使用して元の順序を復元しました。例えば:
SELECT
mf.name
,mf.physical_name
,reverse(left(reverse(physical_name), charindex('\', reverse(physical_name)) -1))
from sys.master_files mf
サブフォルダー内のネストの深さに関係なく、「物理名」から実際のデータベースファイル名を抽出する方法を示します。これは1文字(バックスラッシュ)のみを検索しますが、より長い検索文字列のためにこれを構築できます。
唯一の欠点は、これがTEXTデータ型でどの程度うまく機能するかわかりません。私は数年前からSQL 2005を使用しており、TEXTの操作に精通していませんが、左と右を使用できることを思い出すようです。
フィリップ
最も簡単な方法は....
REVERSE(SUBSTRING(REVERSE([field]),0,CHARINDEX('[expr]',REVERSE([field]))))
Sqlserver 2005以降を使用している場合、REVERSE
関数を何度も使用するとパフォーマンスが低下しますが、以下のコードの方が効率的です。
DECLARE @FilePath VARCHAR(50) = 'My\Super\Long\String\With\Long\Words'
DECLARE @FindChar VARCHAR(1) = '\'
-- Shows text before last slash
SELECT LEFT(@FilePath, LEN(@FilePath) - CHARINDEX(@FindChar,REVERSE(@FilePath))) AS Before
-- Shows text after last slash
SELECT RIGHT(@FilePath, CHARINDEX(@FindChar,REVERSE(@FilePath))-1) AS After
-- Shows the position of the last slash
SELECT LEN(@FilePath) - CHARINDEX(@FindChar,REVERSE(@FilePath)) AS LastOccuredAt
DECLARE @FilePath VARCHAR(50) = 'My\Super\Long\String\With\Long\Words'
DECLARE @FindChar VARCHAR(1) = '\'
SELECT LEN(@FilePath) - CHARINDEX(@FindChar,REVERSE(@FilePath)) AS LastOccuredAt
これは私にとって非常にうまくいきました。
REVERSE(SUBSTRING(REVERSE([field]), CHARINDEX(REVERSE('[expr]'), REVERSE([field])) + DATALENGTH('[expr]'), DATALENGTH([field])))
古いがまだ有効な質問なので、ここで他の人から提供された情報に基づいて作成したものをここに示します。
create function fnLastIndexOf(@text varChar(max),@char varchar(1))
returns int
as
begin
return len(@text) - charindex(@char, reverse(@text)) -1
end
REVERSE(SUBSTRING(REVERSE(ap_description),CHARINDEX('.',REVERSE(ap_description)),len(ap_description)))
私のためによく働いた
うーん、これは古いスレッドですが、集計テーブルはSQL2000(または他のデータベース)でこれを行うことができます。
DECLARE @str CHAR(21),
@delim CHAR(1)
SELECT @str = 'Your-delimited-string',
@delim = '-'
SELECT
MAX(n) As 'position'
FROM
dbo._Tally
WHERE
substring(@str, _Tally.n, 1) = @delim
集計テーブルは、数字が増加するだけのテーブルです。
substring(@str, _Tally.n, 1) = @delim
は各区切り文字の位置を取得し、そのセットの最大位置を取得します。
集計表は素晴らしいです。以前にそれらを使用したことがない場合は、 SQL Server Central (無料の登録、または単にBug Me Notを使用してください( http://www.bugmenot.com/ view/sqlservercentral.com ))。
*編集:TEXTタイプでLEN()を使用できないため、n <= LEN(TEXT_FIELD)
を削除しました。結果がまだ正しいにもかかわらず、substring(...) = @delim
が残っている限り。
文字列と部分文字列の両方を逆にして、最初の出現を検索します。
これは数年前の質問ですが、...
Access 2010
では、InStrRev()
を使用してこれを行うことができます。お役に立てれば。
他の回答のいくつかは実際の文字列を返しますが、実際のインデックスintを知る必要がありました。そして、それを行う答えは物事を過度に複雑にしているようです。インスピレーションとして他の答えのいくつかを使用して、私は次のことをしました...
最初に、関数を作成しました:
CREATE FUNCTION [dbo].[LastIndexOf] (@stringToFind varchar(max), @stringToSearch varchar(max))
RETURNS INT
AS
BEGIN
RETURN (LEN(@stringToSearch) - CHARINDEX(@stringToFind,REVERSE(@stringToSearch))) + 1
END
GO
次に、クエリでこれを行うことができます。
declare @stringToSearch varchar(max) = 'SomeText: SomeMoreText: SomeLastText'
select dbo.LastIndexOf(':', @stringToSearch)
上記は23(「:」の最後のインデックス)を返すはずです
これが誰かにとって少し楽になることを願っています!
この回答ではMS SQL Server 2008を使用しています(MS SQL Server 2000にアクセスできません)が、OPによると、3つの状況を考慮する必要があります。私がここで答えていないことを試みたから、それらの3つすべてをカバーしています:
0
を返します私が思いついた関数は2つのパラメーターを取ります。
@String NVARCHAR(MAX)
:検索される文字列
@FindString NVARCHAR(MAX)
:@String
の最後のインデックスを取得する単一の文字またはサブストリング
@FindString
の@String
の正のインデックスであるINT
または0
が@FindString
にないことを意味する@String
を返します
関数の機能の説明は次のとおりです。
@ReturnVal
を0
に初期化し、@FindString
が@String
にないことを示しますCHARINDEX()
を使用して、@FindString
の@String
のインデックスを確認します@FindString
の@String
のインデックスが0
の場合、@ReturnVal
は0
のままになります@FindString
の@String
のインデックスが> 0
の場合、@FindString
は@String
にあるため、@FindString
の@String
の最後のインデックスをREVERSE()
を使用して計算します@ReturnVal
の@FindString
の最後のインデックスである正の数である@String
または0
が@FindString
にないことを示す@String
を返します関数作成スクリプト(コピーアンドペースト準備完了)は次のとおりです。
CREATE FUNCTION [dbo].[fn_LastIndexOf]
(@String NVARCHAR(MAX)
, @FindString NVARCHAR(MAX))
RETURNS INT
AS
BEGIN
DECLARE @ReturnVal INT = 0
IF CHARINDEX(@FindString,@String) > 0
SET @ReturnVal = (SELECT LEN(@String) -
(CHARINDEX(REVERSE(@FindString),REVERSE(@String)) +
LEN(@FindString)) + 2)
RETURN @ReturnVal
END
関数を簡単にテストするための少しを以下に示します。
DECLARE @TestString NVARCHAR(MAX) = 'My_sub2_Super_sub_Long_sub1_String_sub_With_sub_Long_sub_Words_sub2_'
, @TestFindString NVARCHAR(MAX) = 'sub'
SELECT dbo.fn_LastIndexOf(@TestString,@TestFindString)
他のバージョンにアクセスできないため、これをMS SQL Server 2008でのみ実行しましたが、これを調べたところ、少なくとも2008+には適しているはずです。
楽しい。
私はそれが非効率的であることを知っていますが、あなたが見つけたウェブサイトによって提供されるソリューションを使用できるようにtext
フィールドをvarchar
にキャストすることを検討しましたか? text
フィールドの長さがvarchar
の長さを超えた場合、レコードが切り捨てられる可能性があるため、このソリューションでは問題が発生することがわかっています(もちろん、パフォーマンスがあまり良くないことは言うまでもありません)。
データはtext
フィールド内にあるため(そしてSQL Server 2000を使用しているため)、オプションは制限されます。
@indexOf = <whatever characters you are searching for in your string>
@LastIndexOf = LEN([MyField]) - CHARINDEX(@indexOf, REVERSE([MyField]))
テストしていません。インデックスが0であるために1つずれている可能性がありますが、@indexOf
文字から文字列の終わりまで切り取るときにSUBSTRING
関数で機能します
SUBSTRING([MyField], 0, @LastIndexOf)
この回答は、OPの要件を満たしています。具体的には、針を1文字以上にすることができ、haystackで針が見つからない場合でもエラーは生成されません。他の回答のほとんど(すべて?)がこれらのEdgeのケースを処理しなかったように思えました。さらに、ネイティブMS SQLサーバーのCharIndex関数によって提供される「開始位置」引数を追加しました。左から右ではなく、右から左に処理することを除いて、CharIndexの仕様を正確に反映しようとしました。たとえば、needleまたはhaystackがnullの場合はnullを返し、haystackでneedleが見つからない場合は0を返します。回避できなかったことの1つは、組み込み関数では3番目のパラメーターがオプションであることです。 SQL Serverのユーザー定義関数では、関数が "EXEC"を使用して呼び出されない限り、すべてのパラメーターを呼び出しで提供する必要があります。 3番目のパラメーターはパラメーターリストに含める必要がありますが、値を指定しなくても、キーワード「default」をプレースホルダーとして指定できます(以下の例を参照)。必要でない場合に追加するよりも、この関数から3番目のパラメーターを削除する方が簡単なため、ここに開始点として含めました。
create function dbo.lastCharIndex(
@needle as varchar(max),
@haystack as varchar(max),
@offset as bigint=1
) returns bigint as begin
declare @position as bigint
if @needle is null or @haystack is null return null
set @position=charindex(reverse(@needle),reverse(@haystack),@offset)
if @position=0 return 0
return (len(@haystack)-(@position+len(@needle)-1))+1
end
go
select dbo.lastCharIndex('xyz','SQL SERVER 2000 USES ANSI SQL',default) -- returns 0
select dbo.lastCharIndex('SQL','SQL SERVER 2000 USES ANSI SQL',default) -- returns 27
select dbo.lastCharIndex('SQL','SQL SERVER 2000 USES ANSI SQL',1) -- returns 27
select dbo.lastCharIndex('SQL','SQL SERVER 2000 USES ANSI SQL',11) -- returns 1
区切り文字が最後に出現する前の部分を取得するには(NVARCHAR
の使用により、DATALENGTH
に対してのみ機能します):
DECLARE @Fullstring NVARCHAR(30) = '12.345.67890.ABC';
DECLARE @Delimiter CHAR(1) = '.';
SELECT SUBSTRING(@Fullstring, 1, DATALENGTH(@Fullstring)/2 - CHARINDEX(@Delimiter, REVERSE(@Fullstring)));
このコードは、部分文字列に複数の文字が含まれている場合でも機能します。
DECLARE @FilePath VARCHAR(100) = 'My_sub_Super_sub_Long_sub_String_sub_With_sub_Long_sub_Words'
DECLARE @FindSubstring VARCHAR(5) = '_sub_'
-- Shows text before last substing
SELECT LEFT(@FilePath, LEN(@FilePath) - CHARINDEX(REVERSE(@FindSubstring), REVERSE(@FilePath)) - LEN(@FindSubstring) + 1) AS Before
-- Shows text after last substing
SELECT RIGHT(@FilePath, CHARINDEX(REVERSE(@FindSubstring), REVERSE(@FilePath)) -1) AS After
-- Shows the position of the last substing
SELECT LEN(@FilePath) - CHARINDEX(REVERSE(@FindSubstring), REVERSE(@FilePath)) AS LastOccuredAt
まったく同じ要件を持っているが、REVERSE
関数も欠けている別の種類のデータベースのための、同様の問題の解決策を探しているときに、このスレッドに出会いました。
私の場合、これはOpenEdge(Progress)データベースの場合で、構文が少し異なります。これにより、INSTR
関数が利用可能になりました ほとんどのOracle型付きデータベースが提供 。
そこで、次のコードを思い付きました。
SELECT
INSTR(foo.filepath, '/',1, LENGTH(foo.filepath) - LENGTH( REPLACE( foo.filepath, '/', ''))) AS IndexOfLastSlash
FROM foo
ただし、OpenEdge(Progress)データベースである特定の状況では、文字を空の文字に置き換えると元の文字と同じ長さになるため、これは望ましい動作になりませんでした文字列。これはあまり意味がありませんが、以下のコードで問題を回避できました。
SELECT
INSTR(foo.filepath, '/',1, LENGTH( REPLACE( foo.filepath, '/', 'XX')) - LENGTH(foo.filepath)) AS IndexOfLastSlash
FROM foo
今、私はこの変数がT-SQLの問題を解決しないことを理解しています。これは、INSTR
プロパティを提供するOccurence
関数に代わるものがないためです。
念のため、このスカラー関数を作成するために必要なコードを追加して、上記の例と同じように使用できるようにします。
-- Drop the function if it already exists
IF OBJECT_ID('INSTR', 'FN') IS NOT NULL
DROP FUNCTION INSTR
GO
-- User-defined function to implement Oracle INSTR in SQL Server
CREATE FUNCTION INSTR (@str VARCHAR(8000), @substr VARCHAR(255), @start INT, @occurrence INT)
RETURNS INT
AS
BEGIN
DECLARE @found INT = @occurrence,
@pos INT = @start;
WHILE 1=1
BEGIN
-- Find the next occurrence
SET @pos = CHARINDEX(@substr, @str, @pos);
-- Nothing found
IF @pos IS NULL OR @pos = 0
RETURN @pos;
-- The required occurrence found
IF @found = 1
BREAK;
-- Prepare to find another one occurrence
SET @found = @found - 1;
SET @pos = @pos + 1;
END
RETURN @pos;
END
GO
明らかなことを避けるために、REVERSE
関数が使用可能な場合、このスカラー関数を作成する必要はなく、次のように必要な結果を得ることができます。
SELECT
LEN(foo.filepath) - CHARINDEX('/', REVERSE(foo.filepath))+1 AS LastIndexOfSlash
FROM foo
フォルダパス内のバックスラッシュの最後からn番目の位置を見つける必要がありました。これが私の解決策です。
/*
http://stackoverflow.com/questions/1024978/find-index-of-last-occurrence-of-a-sub-string-using-t-sql/30904809#30904809
DROP FUNCTION dbo.GetLastIndexOf
*/
CREATE FUNCTION dbo.GetLastIndexOf
(
@expressionToFind VARCHAR(MAX)
,@expressionToSearch VARCHAR(8000)
,@Occurrence INT = 1 -- Find the nth last
)
RETURNS INT
AS
BEGIN
SELECT @expressionToSearch = REVERSE(@expressionToSearch)
DECLARE @LastIndexOf INT = 0
,@IndexOfPartial INT = -1
,@OriginalLength INT = LEN(@expressionToSearch)
,@Iteration INT = 0
WHILE (1 = 1) -- Poor man's do-while
BEGIN
SELECT @IndexOfPartial = CHARINDEX(@expressionToFind, @expressionToSearch)
IF (@IndexOfPartial = 0)
BEGIN
IF (@Iteration = 0) -- Need to compensate for dropping out early
BEGIN
SELECT @LastIndexOf = @OriginalLength + 1
END
BREAK;
END
IF (@Occurrence > 0)
BEGIN
SELECT @expressionToSearch = SUBSTRING(@expressionToSearch, @IndexOfPartial + 1, LEN(@expressionToSearch) - @IndexOfPartial - 1)
END
SELECT @LastIndexOf = @LastIndexOf + @IndexOfPartial
,@Occurrence = @Occurrence - 1
,@Iteration = @Iteration + 1
IF (@Occurrence = 0) BREAK;
END
SELECT @LastIndexOf = @OriginalLength - @LastIndexOf + 1 -- Invert due to reverse
RETURN @LastIndexOf
END
GO
GRANT EXECUTE ON GetLastIndexOf TO public
GO
ここに合格する私のテストケースがあります
SELECT dbo.GetLastIndexOf('f','123456789\123456789\', 1) as indexOf -- expect 0 (no instances)
SELECT dbo.GetLastIndexOf('\','123456789\123456789\', 1) as indexOf -- expect 20
SELECT dbo.GetLastIndexOf('\','123456789\123456789\', 2) as indexOf -- expect 10
SELECT dbo.GetLastIndexOf('\','1234\6789\123456789\', 3) as indexOf -- expect 5
単語の文字列の最後のスペースのインデックスを取得する場合、この式RIGHT(name、(CHARINDEX( ''、REVERSE(name)、0))を使用して、文字列の最後の単語を返すことができます。名またはミドルネームのイニシャルを含むフルネームのラストネームを解析する場合に役立ちます。