2

UserRolesという名前のフィールドに格納されているアイテム(整数)のリストを含む列名MyRolesがあります。特定のアイテムがリストにあるかどうかを確認するクエリを作成したいと思います。リストは次のようになります:「1,2,3」

WHEREMyRolesを使用できません

クエリはどのようになりますか?

これは私が考えていることと似ています:

SELECT *
FROM MyTable
WHERE MyRoles CONTAINS ('1')

答えが簡単に実装できず、醜い道をさらに進んでしまうという事実は、正規化されたデータベースが常に最善の策であることを明確に示しています。

4

5 に答える 5

2

あなたが使用することができますLIKE

SELECT *
FROM MyTable
WHERE MyRoles LIKE ('%1%')

これは非常にパフォーマンスが悪い可能性があります(インデックスはそのような検索にはかなり役に立たないため)。そしてもちろん、クエリに存在しない10場合でも一致します。1アプローチを拡張できます。

SELECT *
FROM MyTable
WHERE MyRoles = '1'
  OR MyRoles LIKE '1,%'
  OR MyRoles LIKE '%,1,%'

より良い解決策は、データベースを正規化し、複数値のフィールドを持たないことです。行ごとに単一のロールIDとアイテムIDを持つ多対多のテーブルを使用します。これはクエリがはるかに簡単です。

一部のデータベースには、このようなクエリのためのより優れた機能がありますが、これらは拡張機能であり、標準のSQLではありません。特定のRDBMSについては言及していません。

于 2011-06-15T19:32:22.440 に答える
1

LIKEを使用する場合は注意してください。

MyRolesがそうであれば、あなたはそれを望まないのに2,11、それは一致するでしょう。LIKE('%1%')

苦痛な回避策は使用することです

SELECT *
FROM MyTable
WHERE MyRoles LIKE ('%,1,%')

ただし、すべてのMyRolesエントリに先頭と末尾のコンマを入れる必要があります。

これらのさまざまな醜い事実が、データベース設計を変更して「ロール」テーブルを作成するように誰もがあなたに言っている理由です。

于 2011-06-15T19:36:36.953 に答える
0

正規表現がここで役立つかもしれません:

SELECT *
FROM MyTable
WHERE MyRoles ~ ('^(.*,)*' || 1 || '(,.*)*$')
于 2011-06-15T20:05:08.747 に答える
0
SELECT *
FROM MyTable
WHERE FIND_IN_SET(1, MyRoles)

編集: それはmysqlデータベースサーバーで動作します。

編集:

find_in_set functionpostgresの場合:

create function find_in_set(n int, s text) returns bigint as
$$
select z.row_number
from
(
    select row_number() over(), y.x
    from (select unnest(('{' || $2 || '}')::int[]) as x) as y
) as z
where z.x = $1
$$ language sql;
于 2011-06-15T19:33:36.117 に答える
0

それを配列に変換します:

SELECT *
FROM MyTable
WHERE ('{' || MyRoles || '}')::int[] && array[1]

さらに良いことに、上記の混乱にインデックスを使用することができます。配列型にテキストを完全にキャストすると、配列を作成するときに拒否されますが、回避することができます。

create function role_scan(text) returns int[] as $$
  select ('{' || $1 || '}')::int[];
$$ language sql immutable strict;

create index on MyTable using gin (role_scan(MyRoles));

-- actually use the index
SELECT *
FROM MyTable
WHERE role_scan(MyRoles) && array[1]

インデックスの追加には注意が必要です。統計コレクターは、実際の配列値を調べません(とにかく9.1まで)。オーバーラップ演算子の選択性(1/200、つまり非常に選択的)は、すべての目的と目的のためにハードコーディングされています。したがって、非常に一般的な値に対してクエリを実行している場合、不適切な場所でインデックススキャンが実行される可能性があります。回避策の1つは、多くの役割が適用されることがわかっている場合に、基になるオーバーラップメソッドを直接呼び出すことです(これにより、1/3の選択性が得られ、潜在的なインデックススキャンは行われません)。

SELECT *
FROM MyTable
WHERE arrayoverlap(role_scan(MyRoles), array[1])
于 2011-06-15T20:13:47.100 に答える