0

我被要求建立一个包含一堆位字段的表来切换一系列选项。这是 ac# 标志枚举将所有这些位组合到表中的单个 int“选项”字段中的理想场所。

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

4

3 回答 3

1

我认为您的意思是您在 sql 的 Flag Enum 中设置了 10 个选项,并且您想将其作为 int 值保存到数据库中

例如

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

如果你需要用 C# 以外的东西来检查这个,你只需要使用 Bit Wise 操作来查看检查的内容。这可以使用 & 运算符在 SQL 中完成(检查这里),我想大多数语言也会有一些位植入。

于 2014-06-05T13:57:48.863 回答
1

这是 ac# 标志枚举将所有这些位组合到表中的单个 int“选项”字段中的理想场所。

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

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

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

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

于 2014-06-05T13:29:09.400 回答
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')
    );
于 2014-06-06T03:35:43.243 回答