2

PostgreSQLデータベースに次のテーブルがあります。

CREATE TABLE maclist (
    username character varying,
    mac macaddr NOT NULL,
    CONSTRAINT maclist_user_mac_key UNIQUE (username, mac)
);

MACアドレスがユーザーに割り当てられているかどうか、またはユーザーにMACアドレスがまったく割り当てられていないかどうかを確認する方法が必要です。基本的に、すべての条件が真であるか、条件が真でない場合、つまりXORではない場合に行を返すクエリが必要です。

編集: 例:

username | mac
john     | 11:22:33:44:55:66
john     | 11:22:33:44:55:67
doe      | 11:22:33:44:55:68

クエリした場合:

username = john, mac = 11:22:33:44:55:66                     -> true, 1 whatever...
username = john, mac != 11:22:33:44:55:66                    -> 0, null or nothing...
username = jane, mac = no matter what except john's or doe's -> true, 1 whatever...
username = jane, mac = john's or doe's                       ->  0, null or nothing...

私はtrue2つの条件の下で必要です:

  1. その(ユーザー、Mac)の組み合わせの行があります。行はありません
  2. そのユーザーの場合、およびそのMacの行はありません

これまでのところ私はこれを手に入れました:

SELECT yes
FROM
  (SELECT 1 AS yes) AS dummy
LEFT JOIN maclist ON (username = 'user'
                      OR mac = '11:22:33:44:55:66')
WHERE ((username = 'user'
        AND mac = '11:22:33:44:55:66')
       OR (username IS NULL
           AND mac IS NULL);

それは機能しますが、私にはハックのように見えます。また、データベースが大きくなるにつれて、このクエリのパフォーマンスについてもわかりません。私の質問は、これを行うためのより良い方法があるかどうかです。

4

3 に答える 3

3

編集:私はロジックを少し修正しました、私はそれがあなたが望むものと一致すると思います

次のコードは1、2つの条件下で返されます...

  • そのための行がありuserますmac
  • 0そのユーザー用の行あり、そのための0行がありますmac

他のすべての条件下では、クエリはを返します0

  • そのための行はありますがuser、どれもそのためのものではありませんmac
  • そのための行はありますがmac 、どれもそのためのものではありませんuser


SELECT
  CASE WHEN COUNT(*) = 0                                THEN 1
       WHEN SUM(CASE WHEN mac = '11:22:33:44:55:66'
                      AND user = 'user' THEN 1
                                        ELSE 0 END) = 1 THEN 1
                                                        ELSE 0
  END
FROM
  maclist
WHERE
     username = 'user'
  OR mac      = '11:22:33:44:55:66'
于 2012-11-21T09:29:49.097 に答える
1

クエリは次のように簡単に記述できます。

prepare query_mac(text, macaddr) as
select exists (select 1 from maclist where username = $1 and mac = $2)
       or (not exists (select 1 from maclist where username = $1)
           and not exists (select 1 from maclist where mac = $2)
          );

PostgreSQLは、3つのクエリをそれぞれ個別に評価(username,mac)し、最初の2つに一意のインデックスを使用します。必要に応じて(mac)、3番目のインデックスを追加できます。

于 2012-11-21T11:04:30.903 に答える
0

が含まれている場合、実質的にすべてのデータベースがインデックスを使用するわけではないためOR、結合に含まれるデータベースは避けてください。

編集:

あなたは本当に2つの別々のクエリを行っているようです:

  • 誰に割り当てられたマック(もしあれば)
  • ユーザーに割り当てられているMac(存在する場合)

したがって、結合は副選択のコレクションほど簡単ではありません。個別のクエリを使用して、情報を独自の単純なクエリに分割し、それらを1つに結合します。

select
    (select username from maclist
     where mac = '11.22:33:44:55:66') as mac_assigned_to,
    (select mac from maclist
     where username = 'user') as user_assigned_to

現在割り当てられているものがない場合は、両方の列にnullが含まれる場合があります。そうでない場合は、各懸念事項に割り当てられているものが表示されます。

于 2012-11-21T09:39:35.597 に答える