我被要求构建一个包含一堆位字段的表来切换一系列选项。对于c#标志枚举来说,这是一个完美的地方,只需将所有这些位组合成一个int"选项"表中的字段。
问题是除了c#之外还需要在sql查询中读取和查询这些标志。我找不到任何似乎能够将int解构为一系列标志值的东西。我正在寻找(我认为)是将int转换回二进制然后选择第n个值并将其作为特定选项的bool报告的内容。我可以手动执行此操作,但我担心性能损失加上你的@ss绕过你的肘部"只是试图用过于复杂的解决方案来避免一连串的列。
答案 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')
);