1

ビットフィールドとして使用されているint値を持つテーブルがあります(各ビットはフラグです)。

ここで、次のように2項演算(私の場合はOR)を使用してそれらを集約したいと思います。

SELECT 1 AS bitfield
INTO #TABLE
UNION ALL SELECT 1 + 2 + 8 + 32
UNION ALL SELECT 2 + 128
UNION ALL SELECT 2 + 32

SELECT AND_AGGR(bitfield) -- Invalid because AND_AGGR doesn't exist
FROM #TABLE

DROP #TABLE

値になります171

|うまくいけば多くのとを必要としないこれを行うための良い方法は何でしょうかMAX(しかし、あなたがしなければならないなら、あなたはしなければなりません)?

私は自分でMSSQLServer 2008を使用していますが、他のサーバーのソリューションにも関心があります。

4

3 に答える 3

2

MySQLとPostgreSQLではを使用できますBIT_OR

SQLServerにはこの集計関数はないと思います。

MAXあなたが言ったように、あなたはたくさんでそれをすることができます&

MAX(x & 1) + MAX(x & 2) + ... + MAX(x & 128)
于 2012-04-19T10:14:45.120 に答える
1

あなたが結果を期待しているなら171、確かにあなたはバイナリORではなくバイナリを意味しANDますか?

いずれの場合も、このソリューションは値を変数に集約します。

SELECT 1 AS bitfield
INTO #TABLE
UNION ALL SELECT 1 + 2 + 8 + 32
UNION ALL SELECT 2 + 128
UNION ALL SELECT 2 + 32

DECLARE @i int = 0

SELECT @i = @i | bitfield
FROM #TABLE

SELECT @i

DROP TABLE  #table

別のフィールドで集計をグループ化する場合、これは要件を満たさない可能性があります。

また、大きなテーブルではうまく機能しない可能性があります。

于 2012-04-19T10:25:18.733 に答える
0

MSSQLServerの場合

DECLARE @agg  VARCHAR(MAX) = '0001,0011,0101,0101,0101'
SELECT CONVERT(binary(4), VALUE, 2) , VALUE  FROM STRING_SPLIT( @agg , ',')

DECLARE @sum AS BIGINT = 0
DECLARE @mul AS BIGINT = 0xffffffff
SELECT  @sum |= v
   , @mul &= v
FROM STRING_SPLIT( @agg , ',')
CROSS APPLY (VALUES (CONVERT(binary(4), VALUE, 2))) _(v)

PRINT FORMAT(@sum,'X8')
PRINT FORMAT(@mul,'X8')

プリント

            VALUE
---------- ------------
0x00010000 0001
0x00110000 0011
0x01010000 0101
0x01010000 0101
0x01010000 0101

01110000
00010000

より複雑な言葉であなたが必要とする:

CREATE OR ALTER FUNCTION dbo.BOR( @agg VARCHAR(MAX))
RETURNS BIGINT
AS 
BEGIN
DECLARE @sum AS BIGINT = 0
SELECT  @sum |= CONVERT(BIGINT, VALUE)
FROM STRING_SPLIT( @agg , ',')
RETURN @sum
END

GO
CREATE OR ALTER FUNCTION dbo.BAND( @agg VARCHAR(MAX))
RETURNS BIGINT
AS 
BEGIN
DECLARE @mul AS BIGINT = 0xffffffffffffffff
SELECT  @mul &= CONVERT(BIGINT, VALUE)
FROM STRING_SPLIT( @agg , ',')
RETURN @mul
END
GO

支払い期間のビットマップを使用する場合

;WITH delayedPayment AS
(SELECT * FROM ( VALUES 
    ( 123, 67, '2020-2-1')
   ,( 123, 67, '2020-4-1')
   ,( 123, 67, '2020-5-1')
   ,( 123, 67, '2020-6-1')
   ,( 123, 68, '2020-6-1')  -- another agreement
   ,( 123, 67, '2020-12-1')
           
   ,( 456, 69, '2020-4-1')
   ,( 456, 69, '2020-8-1')
   ,( 456, 69, '2020-10-1')
   ,( 456, 69, '2020-11-1')) _(cuno, loan, missedDuedate)
)
, delayPattern AS
(SELECT cuno
   ,  sum_months
   ,  bor_months
   ,  IIF( FORMAT( CAST(bor_months AS BIGINT), 'X16') LIKE '%111%', 'dalyad 3+ month in row', NULL) delayState
   FROM (SELECT cuno
         , SUM(POWER( 16.0, CONVERT( BIGINT, DATEDIFF( month, missedDuedate, '2020-12-1')))) sum_months
         , dbo.BOR( STRING_AGG( CONVERT( BIGINT, POWER( 16.0, DATEDIFF( month, missedDuedate, '2020-12-1'))),',')) bor_months
      FROM delayedPayment
      GROUP BY cuno
   ) s
)
SELECT cuno
   ,  FORMAT( CAST(sum_months AS BIGINT), 'X16') sum_months
   ,  FORMAT( CAST(bor_months AS BIGINT), 'X16') bor_months
   ,  delayState
FROM delayPattern

cuno    sum_months          bor_months          delayState
123     00000*10112*000001  00000*10111*000001  dalyad 3+ month in row
456     0000000100010110    0000000100010110    NULL

しかし、たまに1つだけ考える必要があり、SUMでそれを行うことができます

, delayPattern AS -- optimal
(SELECT cuno
   ,  bor_months
   ,  IIF( FORMAT( CAST(bor_months AS BIGINT), 'X16') LIKE '%111%', 'dalyad 3+ month in row', NULL) delayState
   FROM (SELECT cuno
         , SUM(POWER( 16.0, missedmonth)) bor_months
      FROM ( SELECT DISTINCT cuno
               , missedmonth
            FROM delayedPayment
            CROSS APPLY (VALUES ( DATEDIFF( month, missedDuedate, '2020-12-1'))) _(missedmonth)
            GROUP BY cuno, missedmonth
            ) ss
      GROUP BY cuno
   ) s
)

SELECT cuno
   ,  FORMAT( CAST(bor_months AS BIGINT), 'X16') bor_months
   ,  delayState
FROM delayPattern

印刷します

cuno    bor_months  delayState
123 0000010111000001    dalyad 3+ month in row
456 0000000100010110    NULL

注:私はHEX形式とPOWER(16.0、X)を使用していますが、怠惰になるために、POWER(2.0、X)は正しいですが、bin->stringフォーマッターが必要です。このようなもの:

CREATE OR ALTER FUNCTION dbo.toBinaryString(@p INT)
RETURNS VARCHAR(24)
AS 
BEGIN 
RETURN  REVERSE(REPLACE( REPLACE( 
    REPLACE( REPLACE( REPLACE( REPLACE( 
    REPLACE( REPLACE( REPLACE( REPLACE( 
    REPLACE( REPLACE( REPLACE( REPLACE( 
    REPLACE( REPLACE( REPLACE( REPLACE( FORMAT(@p,'X8'), 
        '0', '....'), '1', '...x'),'2', '..x.'),'3', '..xx'),
        '4', '.x..'), '5', '.x.x'),'6', '.xx.'),'7', '.xxx'),
        '8', 'x...'), '9', 'x..x'),'A', 'x.x.'),'B', 'x.xx'),
        'C', 'xx..'), 'D', 'xx.x'),'E', 'xxx.'),'F', 'xxxx'),
        '.','0'),'x','1'))
END
于 2021-06-27T17:07:56.390 に答える