SQLServerでのMidB関数

レガシーマイグレーションで帳票の印字内容で全角・半角文字を意識した処理があり、バイト数指定の文字列関数が必要になりました。
http://blogs.sqlpassj.org/yoshihirokawabata/archive/2006/08/03/17581.aspxにLeftB, RightBはあったので、MidB関数の第3引数省略版を作りました。

LeftB, RightBの類推で作るとこんな感じ。

CREATE FUNCTION MidB
(
    @value varchar(8000),
    @start int,
    @length int
)
RETURNS varchar(8000)
AS
BEGIN
    RETURN convert(varchar(8000), 
        substring(convert(text, @value), @start, @length))
END
GO

第3引数を省略したバージョンはこちら。

CREATE FUNCTION AfterB
(
    @value varchar(8000),
    @start int
)
RETURNS varchar(8000)
AS
BEGIN
    RETURN convert(varchar(8000), 
        substring(convert(text, @value), @start, datalength(convert(text, @value)) - @start + 1))
END
GO

しかし、切り出す境界で2バイト文字をまたいでしまうとまずいです。。。うーん。。。

LeftB関数の戻り値は2バイト文字をまたいで切り出しても、切り捨ててくれるようですのでAfterB関数はこれを利用します。

/*
 AfterB: 第3引数を省略したバイト単位の Mid (substring) ユーザー定義関数

 ■実行例
   dbo.AfterB('あいうえお', 5) = 'うえお'

 参考:http://blogs.sqlpassj.org/yoshihirokawabata/archive/2006/08/03/17581.aspx
*/

CREATE FUNCTION AfterB
(
    @all varchar(8000),
    @start int
)
RETURNS varchar(8000)
AS
BEGIN
    DECLARE @left varchar(8000)
    SET @left = dbo.LeftB(@all, @start - 1)
    RETURN substring(@all, len(@left) + 1, len(@all) - len(@left)1)
END
GO

下記のクエリを実行して確認します。意図どおりのようです。

SELECT DATALENGTH(dbo.LeftB('あいうえお', 3)),DATALENGTH(dbo.AfterB('あいうえお', 4))

MidB関数はAfterB関数の戻り値を利用して、こうしてみます。

/*
 MidB: バイト単位の Mid (substring) ユーザー定義関数

 ■実行例
   dbo.MidB('あいうえお', 5, 2) = 'う'

 参考:http://blogs.sqlpassj.org/yoshihirokawabata/archive/2006/08/03/17581.aspx
*/

CREATE FUNCTION MidB
(
    @value0 varchar(8000),
    @start int,
    @length int
)
RETURNS varchar(8000)
AS
BEGIN
    DECLARE @value varchar(8000)
    SET @value = dbo.AfterB(@value0, @start - 1)
    RETURN dbo.LeftB(@value, @length)
END
GO

MidB関数の仕様が妥当かは検討の余地がありますが、2バイト文字をぶった切るために起こる文字化けを防げますし、とりあえずこうしておきます。

#今回のお仕事で必要なのはAfterB関数だけだし。:-P

PASSJの河端様にはいつも助けられてます。m(_ _)m