SQLとフラグ

もちろん、それはSQLサーバーのCapture The Flagゲームモードではなく、ビットフラグの使用に関するものです。 ビット操作は、環境や開発言語に関係なく、おそらくパン操作に関係するすべての人によく知られています。 しかし、私の意見では、フラグの使用は日常的なツールよりも多くの人にとってエキゾチックです。 Habréでは、enumを介してフラグを操作する便利な.NET機能の可能性が何度も言及されていますが、SQLを使用するとフラグを使用する絶好の機会も得られます。

それで、簡単な例を見てみましょう-特定のアプリケーションでは、特定のユーザー通知システムがあるはずです。 フォーラムを構築していて、ユーザーがメールで通知を受信できるようにするとします:選択したトピックの新しい応答、新しい個人的なメッセージ、フォーラムニュースタスクを簡単に確認すると、簡単なテーブルデザインが得られます。
tblUsers {userID(PK)int、name as nvarchar(50)、password as nvarchar(50)}
tblUserAlerts {intとしてのuserID(FK)、intとしてのalertID(FK)}
tblAlerts {intとしてのアラートID(PK)、nvarcharとしてのメッセージ(50)}


つまり、ユーザーテーブル、アラートのテーブルがあり、各ユーザーが複数のアラートを選択できるようにするために、それらの関係は補助テーブルを介して実装されます。 データは次のようになります。
tblUsers
1、「Vasya」、「slypryp4r0l」

tblUserAlerts
1、1

tblAlerts
1、「新しいプライベートメッセージを受信しました」

次に、フラグを使用した例を見てみましょう。
tblUsers {ユーザーID(PK)int、名前nvarchar(50)、パスワードnvarchar(50)、アラートint}、
tblAlerts {intとしてのアラートID(PK)、nvarcharとしてのメッセージ(50)}

このオプションでは、同じ機能を取得し、追加のテーブルなしで実行します。 tblAlertsテーブルでは、同じintを使用してalertIDをフラグビットとして設定し(サイズはアラートオプションの数によって異なります)、tblUsersテーブルでは、アラートフィールドにアラートマスクビットが表示されます。 3種類のアラートを作成するとします。したがって、tblAlertsテーブルには、alertIDフィールドにフラグがある4(アラートなし+前述の3タイプ)行があります。 最初のIDは0になります-ビットでは、それぞれ0000の値になります-通知はありません。 次に、毎回異なるビットを点灯してアラートを追加します(各識別子は2の累乗になります):0001 = 1、0010 = 2、0100 = 4:
tblAlerts
0、NULL
1、「選択したトピックの新しい回答」
2、「新しいプライベートメッセージを受信しました」
4、「ニュースがあります!」

次に、たとえば、ニュースやプライベートメッセージに関するアラートにユーザーを登録する必要があります。 これを行うには、これらのアラートの識別子を要約し、0110 = 6を取得します。
tblUsers
1、「Vasya」、「slypryp4r0l」、6

次に、tblUsersテーブルにクエリを作成して、ニュースを購読しているユーザーを見つけましょう。
SELECT * FROM tblUsers WHERE (tblUsers.alert & 4) > 0

この操作の意味は簡単です:
0110-マスク
0100-ニュースフラグ
0100-結果(つまり、マスクとフラグの共通部分がある場合、結果はゼロより大きくなります)

良い面-あなたは比較してマスクすることができます。 すべてのタイプのアラート1 + 2 + 4 = 7にサブスクライブしているユーザーのリストを取得するとします。
SELECT * FROM tblUsers WHERE (tblUsers.alert & 7) = 7

マスク6と7の間に交差点がありますが、結果は7とは異なることに注意してください
0110-ユーザーマスク
0111-検証マスク
0110-結果(7または6の交差または最小= 6)

同様に、返信の通知またはプライベートメッセージの通知1 + 2 = 3のいずれかにサブスクライブしているユーザーのリストに要求を行うことができます。
SELECT * FROM tblUsers WHERE (tblUsers.alert & 3) > 0

肯定的な結果は、1、2、および3の値(つまり、2つのアラートのいずれか、または両方)でユーザーマスクをチェックすると見なされます。

このような簡単な方法で、ミドルウェアテーブルを削除し、クエリを簡素化することもできます。 ただし、標準では識別子が比較されるため、標準の視覚的なクエリエディターを介して何らかのアクション(JOINなど)を実行することはできない場合があります。 比較をビット操作で手動で置き換える必要があります。
SELECT tblUsers.*, tblAlerts.*
FROM tblUsers INNER JOIN tblAlerts ON (tblUsers.alerts & tblAlerts.alertID) = tblAlerts.alertID

Source: https://habr.com/ru/post/J68322/


All Articles