簡體   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