とりあえず改良 LEN 関数 (U_LEN)

使う場合は自己責任で。

-- =============================================
-- Author:      bleis-tift
-- Create date: 2009/5/17
-- Description: サロゲート文字を考慮した文字列長を取得します。
-- =============================================
CREATE FUNCTION U_LEN 
(
  @str nvarchar(max)
)
RETURNS int
AS
BEGIN
  /*
   * UTF-16ではUnicodeのスカラ値000uuuuuxxxxxxxxxxxxxxxxを、
   * 110110wwwwxxxxxx 110111xxxxxxxxxxの2バイトで表す(wwwwはuuuuu-1)。
   * この先頭のビット列110110を判定するために、
   * 1111110000000000(十進数で64512)をマスクとし、ビットごとに論理積を取った際、
   * 1101100000000000(十進数で55296)と等しくなればサロゲート文字とみなす。
   */
  DECLARE @MASK AS int;
  DECLARE @SURROGATE_PAT AS int;
  SET @MASK = 64512;
  SET @SURROGATE_PAT = 55296;
  
  DECLARE @result AS int;
  SET @result = 0;
  
  DECLARE @i AS int;
  DECLARE @len AS int;
  SET @i = 1;
  SET @len = LEN(@str);
  
  DECLARE @is_surrogate AS bit;
  SET @is_surrogate = 0;
  WHILE @i <= @len BEGIN
    DECLARE @ch AS int;
    SET @ch = UNICODE(SUBSTRING(@str, @i, 1));
    
    IF @is_surrogate = 1
      SELECT
          @result = @result + 1
        , @is_surrogate = 0
      ;
    -- サロゲートペアのパターンに一致した段階では結果をインクリメントしない
    ELSE IF @ch & @MASK = @SURROGATE_PAT
      SET @is_surrogate = 1;
    ELSE
      SET @result = @result + 1;
    
    SET @i = @i + 1;
  END
  
  RETURN @result;
END