2

1 つのバイナリ列を持つテーブルがあります。0x00010100000101010101......00 列のデータ長が 35040 を含む、このデータを次のように準備します

@Jobbyte = COALESCE(@Jobbyte , 0x) + Cast ((Case When Sum(A.bit) >= 1 then 1 else 0 end)as binary(1))

このバイナリ データを別のバイナリ データと比較し、一致するバイナリ カウントを取得する必要があります。両方のバイナリ データのデータの長さが等しい

下の画像を見てください。Binary1 と Binary2 の 2 つのバイナリ データです。両方のバイナリ データを比較し、一致するバイナリ データの合計を取得したいと考えています。唯一の条件は、binary2 のシングル ビットが 0x01 の場合です。

最後の行は、0 = 一致しない、1 = 一致し、最後の列は最後の行の合計であることを示します (4) 比較する方法を教えてください。クエリを投稿できるとよいでしょう。

更新 1


私は2つの関数を使用して解決しようとしていますが、10000レコードで実行すると時間がかかり、1レコードの実行時間は50ミリ秒です

Create FUNCTION [dbo].[Fn_BinaryToTable]
(   
    @BinaryData VARBINARY(max)
)
RETURNS TABLE 
AS
RETURN 
(
    Select  ((N.Number / 96) - (Case (N.Number % 96) when 0 Then 1 else 0 end))+1 As [FNNoDay],
            (Case (N.Number % 96) when 0 then 96 else (N.Number % 96) end) * 15  AS [FnMinutes],
            SUBSTRING(@BinaryData,(N.Number),1) AS [FNBIT]
    from    Numbers N 
    Where N.Number between 1 and (DATALENGTH(@BinaryData))
)
---------------------------------------------------------
Create FUNCTION [dbo].[fn_GetPercentage]
(
    @JobValue int,  
    @CandidateBinary VARBINARY(max),
    @JobBinary VARBINARY(max)
)
RETURNS Decimal
AS
BEGIN
    DECLARE @RValue Decimal;

    SELECT  @RValue = SUM(cast(JB.FNBIT as int))            
    FROM    dbo.Fn_BinaryToTable(@CandidateBinary)   CB,
            dbo.Fn_BinaryToTable(@JobBinary) JB
    WHERE   CB.FNNoDay = JB.FNNoDay
      AND   CB.FnMinutes = JB.FNMinutes
      AND   JB.FNBIT = CB.FNBIT
      AND   JB.FNBIT = 0x01

    Return ((@RValue * 100)/ @JobValue);
END
--------------------------------------------------------
Declare @Jobbyte varbinary(max);
Declare @JobValue int; 

Select @Jobbyte = JobBinary from Job;
Select @JobValue = count(*) from dbo.Fn_BinaryToTable(@Jobbyte) Where FNBIT = 0x01

----Select @JobValue = Sum(Cast(FNBIT as int)) from dbo.Fn_BinaryToTable(@Jobbyte)
set statistics time on
set statistics io on

select cid,dbo.fn_GetPercentage(@JobValue,cal,@Jobbyte) from eCal

set statistics time oFF
set statistics io oFF

----------------------------------------------------------
  • Numbers テーブルには、1 ~ 99999 の値を含む int フィールドが 1 つだけ含まれています。
  • 1 日 15 分間隔で 96 回使用 (24* (60/15))
4

1 に答える 1

0

次のコードを見てください。行を生成し、両方の文字列のセグメントを比較します。

with q as (
    SELECT
        CONVERT(varchar(max), a ,2) a, -- convert 'a' bin data to varchar
        CONVERT(varchar(max), b ,2) b  -- convert 'b' bin data to varchar
    FROM
        (
            SELECT -- a, b - test bin data
                Cast (1 as binary(1)) + Cast (0 as binary(1)) + Cast (1 as binary(1)) a, -- 01 00 01
                Cast (1 as binary(1)) + Cast (1 as binary(1)) + Cast (1 as binary(1)) b  -- 01 01 01 - 2 matches
        ) k
)

select
    --*, substring(a, x + 1, 2), substring(b, x + 1, 2)
    sum(case when 
        substring(a, x + 1, 2) = substring(b, x + 1, 2) -- is block equals
    then 1 else 0 end) sum_of_all_pair_equals
from
    q
        join
    ( -- generate 99999 rows for getting 2 chars block from staring a, b
        select
            x * 10000 + y * 1000 + z * 100 + k * 10 + l as x
        from
            (select 1 x union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9 union select 0) x,
            (select 1 y union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9 union select 0) y,
            (select 1 z union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9 union select 0) z,
            (select 1 k union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9 union select 0) k,
            (select 1 l union select 2 union select 3 union select 4 union select 5 union select 6 union select 7 union select 8 union select 9 union select 0) l
    ) x
        on (
            x between 0 and len(a) - 2 -- start from 1 to len - 2
            and x % 2 = 0 -- get every even x
        )

このクエリはより高速である必要がありますが、パフォーマンスについてはテストしていません。

DECLARE @a VARCHAR(30); -- a bin string
DECLARE @b VARCHAR(30); -- b bin string
DECLARE @itersLeft INT; -- iterations count
DECLARE @i INT; -- counter
DECLARE @outCnt INT; -- result match counter

SELECT
    @a = CONVERT(varchar(max), a ,2), -- convert 'a' bin data to varchar
    @b = CONVERT(varchar(max), b ,2)  -- convert 'b' bin data to varchar
FROM
    (
        SELECT -- a, b - test bin data
            Cast (1 as binary(1)) + Cast (0 as binary(1)) + Cast (1 as binary(1)) a, -- 01 00 01
            Cast (1 as binary(1)) + Cast (1 as binary(1)) + Cast (1 as binary(1)) b  -- 01 01 01 - 2 matches
    ) k
    ;

SET @i = 0; -- init counter
SET @outCnt = 0; -- init result counter
SELECT @itersLeft = LEN(@a) - 2; -- setting max iterations counter

WHILE @i <= @itersLeft
BEGIN
        if substring(@a, @i + 1, 2) = substring(@b, @i + 1, 2) -- compare data
            SET @outCnt = @outCnt + 1; -- increase counter if equals

        SET @i = @i + 2; -- increase counter by block size
END

SELECT @outCnt result; -- selecting result
于 2013-08-30T09:20:35.137 に答える