将Varbinary(max)与另一个Varbinary(max)匹配

时间:2013-08-29 09:34:42

标签: sql sql-server-2008 binary

我有一个包含一个二进制列的表。包含0x00010100000101010101 ...... 00列数据长度为35040, 我准备这样的数据,如

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

我必须将这个二进制数据与另一个二进制数据进行比较,并获得匹配的二进制数。二进制数据都具有相同的数据长度

请看下面的图像,它们是2个二进制数据Binary1和Binary2我想要比较二进制数据并获得匹配二进制数据的总和。只有一个条件是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到的int字段 99999值
  • 96使用15分钟间隔一天(24 *(60/15))

1 个答案:

答案 0 :(得分: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