繁体   English   中英

在T-SQL中解构C#标志

[英]Deconstruct c# flags within t-sql

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

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

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

不它不是。 完美的地方表明您不知道SQL中的16位字段在存储中已优化。 它是您创建维护噩梦并演示可以使用反模式的理想场所。

我什么都找不到,似乎无法将int分解为一系列标志值

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

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

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

例如

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

如果您需要使用C#以外的其他方式进行检查,则只需使用位明智操作即可查看所检查的内容。 这可以在SQL中使用&运算符( 请在此处检查 )来完成,我想大多数语言也会有一些明智的选择。

为了好玩,我将直接回答您的问题。 对于大数据,这将无法很好地执行,但许多位列也将无法执行。

我认为您的总体设计的答案是具有正确的数据库设计,没有一堆位列,并且仍然表现良好,是从主表中创建一个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')
    );

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM