简体   繁体   中英

Deconstruct c# flags within t-sql

I am being asked to build a table with a bunch of bit fields to toggle a series of options. This is a perfect place for ac# flag enum to just combine all of these bits into a single int "options" field in the table.

Problem is that there are things other than c# that will need to read and query off these flags in the sql queries. I could find nothing that seems to be able to deconstruct an int into a series of flag values. What I'm looking for (I think) is something that converts the int back to binary and then picks the n'th value and reports it as a bool of a specific option. I could do this manually but I'm worried about the performance hit plus the "going around your @ss to get to your elbow" effect of just trying to avoid a litany of bit columns with an over complicated solution.

This is a perfect place for ac# flag enum to just combine all of these bits into a single int "options" field in the table.

No, it is not. It is the perfect place to show you are not aware that 16 bit fields in SQL are optimized in storage. And it is the perfect place for you to create a maintenance nightmare and demonstrate you can use an antipattern.

I could find nothing that seems to be able to deconstruct an int into a series of flag values

There is nothing for that. It is an antipattern.

Bit columns. That is how SQL wants it.

I Think what you mean is you have say 10 options on set in a Flag Enum in sql and you want to save this to the database as a int value

eg

[Flags]
public enum Options
{
0 = None
1 = OP1
2 = OP2
4 = OP3
...
}

If you need to check this with something other then C# you would just need to use a Bit Wise operation to see what is checked. This can be done in SQL using the & operator( check here ), I guess most languages will have some implantation of bit wise also.

For fun, I'm going to answer your question directly. Over large data, this will not perform well, but neither will many bit columns.

I think the answer for your overall design to have correct database design, not have a bunch of bit columns, and still perform well is to create a 1 to many table off of your main table, where a record existence means that the option is enabled. This can then be indexed well and perform well. You can also follow a similar construct of lookup table that I'm using below, combined with SUM() across the multiple rows in the child table to convert the multiple records back to your C# enum. Updating the table can also be accomplished with a well crafted MERGE statement. The code for that solution is a little drawn out however and outside the scope of your original question.

CREATE TABLE dbo.Data
    (
        ID int IDENTITY(1,1) NOT NULL PRIMARY KEY,
        Name varchar(50) NOT NULL,
        Flags int NOT NULL DEFAULT(0)
    );

CREATE TABLE dbo.Flag
    (
        Value int NOT NULL PRIMARY KEY,
        Name varchar(50) NOT NULL
    );

INSERT INTO dbo.Flag
    SELECT 1, 'Option A'
    UNION ALL
    SELECT 2, 'Option B'
    UNION ALL
    SELECT 4, 'Option C';

INSERT INTO dbo.Data (Name, Flags)
    SELECT 'George', 0
    UNION ALL
    SELECT 'Bob', 1
    UNION ALL
    SELECT 'Bill', 3;

-- for C#
SELECT
    d.ID,
    d.Name,
    d.Flags
FROM
    dbo.Data d;

-- for other callers vertical
SELECT
    d.ID,
    d.Name,
    d.Flags,
    f.Name AS Flag,
    f.Value
FROM
    dbo.Data d
        LEFT JOIN dbo.Flag f ON
            d.Flags & f.Value = f.Value;

-- for other callers horizontal
SELECT
    p.Name,
    p.[Option A],
    p.[Option B],
    p.[Option C]
FROM
    (
        SELECT
            d.Name,
            f.Name AS Flag,
            f.Value
        FROM
            dbo.Data d
                LEFT JOIN dbo.Flag f ON
                    d.Flags & f.Value = f.Value
    ) d
PIVOT
(
    COUNT(d.Value)
    FOR d.Flag IN ([Option A], [Option B], [Option C])
) p;

SELECT
    d.ID,
    d.Name,
    d.Flags
FROM
    dbo.Data d
WHERE
    EXISTS
    (
        SELECT *
        FROM
            dbo.Flag f
        WHERE
            d.Flags & f.Value = f.Value AND
            f.Name IN ('Option A', 'Option B')
    );

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