在t-sql中解构c#标志

时间:2014-06-05 13:26:44

标签: c# sql-server tsql enum-flags

我被要求构建一个包含一堆位字段的表来切换一系列选项。对于c#标志枚举来说,这是一个完美的地方,只需将所有这些位组合成一个int"选项"表中的字段。

问题是除了c#之外还需要在sql查询中读取和查询这些标志。我找不到任何似乎能够将int解构为一系列标志值的东西。我正在寻找(我认为)是将int转换回二进制然后选择第n个值并将其作为特定选项的bool报告的内容。我可以手动执行此操作,但我担心性能损失加上你的@ss绕过你的肘部"只是试图用过于复杂的解决方案来避免一连串的列。

3 个答案:

答案 0 :(得分:1)

  

这是一个完美的地方,可以将c#标志枚举结合起来   将这些位转换为单个int"选项"表中的字段。

不,不是。它是展示您不知道SQL中的16位字段在存储中进行优化的理想场所。它是您创建维护噩梦并证明您可以使用反模式的理想场所。

  

我找不到任何似乎能够将int解构为一系列旗帜的东西   值

没有什么可以做的。这是一个反模式。

位列。这就是SQL想要它的方式。

答案 1 :(得分:1)

我认为你的意思是你在sql的一个Flag Enum中设置了10个选项,你想把它作为一个int值保存到数据库中

e.g。

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

如果您需要使用C#之外的其他内容进行检查,您只需要使用Bit Wise操作来查看检查的内容。这可以在SQL中使用&运算符(check here),我猜大多数语言也会有一些比特的植入。

答案 2 :(得分:1)

为了好玩,我会直接回答你的问题。对于大数据,这将不会很好,但也不会有很多位列。

我认为你的整体设计有正确的数据库设计的答案,没有一堆位列,并且仍然表现良好是创建一个主表的1对多表,其中记录存在意味着选项已启用。然后可以将其编入索引并且表现良好。您还可以使用我在下面使用的类似查找表结构,并结合子表中多行的SUM()将多个记录转换回C#枚举。更新表也可以使用精心设计的MERGE语句来完成。该解决方案的代码有点抽出,但不在原始问题的范围内。

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')
    );