Store multiple bit values in a single table column

后端 未结 4 644
有刺的猬
有刺的猬 2020-11-30 14:51

I need to store some sort of day-of-week scheduling in database, where I can schedule a record (say it represents a task) for a day or multiple days of the week. I need to h

相关标签:
4条回答
  • 2020-11-30 14:54

    I'm not sure what you mean by easy querying. It is all easy once you wrap it in a function. An option for easy ad hoc querying might be to have easily readable string fields and use some string manipulation processes work it out. Example:

    UPDATE T SET Schedule = 'M|W|H'
    
    SELECT * FROM T WHERE CHARINDEX(Schedule, 'M') > -1
    
    0 讨论(0)
  • 2020-11-30 14:57

    You are talking about a "bit mask". These are handy devices as you can apply binary math on them to easily check the values, but they do take a little setup. To expand on that a little more it would look something like this.

    -- You will want to work with constants
    DECLARE @Mon INT, @Tue INT, @Wed INT, @Thu INT, @Fri INT, @Sat INT, @Sun INT
    
    SET @Mon = POWER(2,0) -- 1
    SET @Tue = POWER(2,1) -- 2
    SET @Wed = POWER(2,2) -- 4
    SET @Thu = POWER(2,3) -- 8
    SET @Fri = POWER(2,4) -- 16
    SET @Sat = POWER(2,5) -- 32
    SET @Sun = POWER(2,6) -- 64
    
    -- Set Monday and Wednesday
    UPDATE T SET Schedule = @Mon | @Wed
    
    -- Find all tasks scheduled on Tuesday
    SELECT * FROM T WHERE Schedule & @Tue = @Tue
    
    -- Find all tasks scheduled on Tuesday and Saturday
    SELECT * FROM T WHERE Schedule & @Tue | @Sat = @Tue | @Sat
    
    0 讨论(0)
  • 2020-11-30 14:57

    From the title, I was led here with a situation of having existing bit fields in a table and needing to convert to a single integer field.

    In following the example of days-of-week, let's say have 7 individual bit fields that you want to convert into a (bit-mask) integer field named Schedule:

    UPDATE T
    SET Schedule = Mon * POWER(2,0) +
                   Tue * POWER(2,1) +
                   Wed * POWER(2,2) +
                   Thu * POWER(2,3) +
                   Fri * POWER(2,4) +
                   Sat * POWER(2,5) +
                   Sun * POWER(2,6)
    
    0 讨论(0)
  • 2020-11-30 15:01

    You could store this as a bitfield and then use boolean logic operators to retrieve the values

    for example:

    CREATE TABLE [dbo].[testBF](
        [field1] [varchar](max) NOT NULL,
        [field2] [varchar](max) NOT NULL,
        [bitfield] [int] NOT NULL CONSTRAINT [DF_testBF_bitfield]  DEFAULT ((0))
    ) ON [PRIMARY]
    

    Then for selects:

    SELECT field1, field2,
           CASE WHEN (bitfield & 1) = 1 THEN 'monday ' ELSE '' END + 
           CASE WHEN (bitfield & 2) = 2 THEN 'tuesday ' ELSE '' END +
           CASE WHEN (bitfield & 4) = 4 THEN 'wednesday ' ELSE '' END +
           CASE WHEN (bitfield & 8) = 8 THEN 'thursday ' ELSE '' END +
           CASE WHEN (bitfield & 16) = 16 THEN 'friday' ELSE '' END as [days of week]
    FROM testBF
    

    To find all days that contain tuesday flag (tuesday is the 2nd bit or 2^1 or 2)

    SELECT * 
    FROM aTable
    WHERE (bitfield & 2) = 2
    

    or

    SELECT * 
    FROM aTable
    WHERE (bitfield & 2) != 0
    

    Note, the template in the second case will work for any bit -- that is for friday (the 5th bit or 2^4 or 16) would be

    SELECT * 
    FROM aTable
    WHERE (bitfield & 16) != 0
    

    Finally the general case... pass in a number (1 for monday) you get

    SELECT * 
    FROM aTable
    WHERE (bitfield & POWER(2,@inNumOfWeekday-1)) != 0
    

    This seems like a lot of work to me, when you could just save it as 5 (or 7 bit fields) but that is how you could do it.

    For more examples look at the gist I wrote for another question:

    https://gist.github.com/1846338

    and the answer:

    https://stackoverflow.com/a/9302106/215752

    0 讨论(0)
提交回复
热议问题