简体   繁体   中英

Match Varbinary(max) with another Varbinary(max)

i have a table with one binary column. that contains 0x00010100000101010101......00 column datalength is 35040, i am prepare this data like

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

i have to compare this binary data with another binary data and get the matching binary count. both the binary data has equal length of data

Please look below image, their is 2 binary data Binary1 and Binary2 i want to compare both binary data and get Sum of matching binary data. only one condition is when binary2's single bit is 0x01

Last Row is indicate 0 = No Match, 1 = Match and last column is Sum of Last row (4) Please suggest me how can i compare , it's better if you can post a query

Update 1


i am doing with 2 function and try to resolve but it's take to much time while execute with 10000 record, execution time for 1 record is 50 Millisecond

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

----------------------------------------------------------
  • A Numbers table contains only one int field that contains 1 to 99999 value
  • 96 use for a 15 Minute interval of one day (24* (60/15))

Please look at next code. It's generate rows and compare segments of both strings:

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
        )

this query must be faster, but I have not tested it for perfomance:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM