質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
Ruby on Rails 5

Ruby on Rails 5は、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

PostgreSQL

PostgreSQLはオープンソースのオブジェクトリレーショナルデータベース管理システムです。 Oracle Databaseで使われるPL/SQLを参考に実装されたビルトイン言語で、Windows、 Mac、Linux、UNIX、MSなどいくつものプラットフォームに対応しています。

SQL

SQL(Structured Query Language)は、リレーショナルデータベース管理システム (RDBMS)のデータベース言語です。大きく分けて、データ定義言語(DDL)、データ操作言語(DML)、データ制御言語(DCL)の3つで構成されており、プログラム上でSQL文を生成して、RDBMSに命令を出し、RDBに必要なデータを格納できます。また、格納したデータを引き出すことも可能です。

Q&A

解決済

4回答

1104閲覧

2カラムの複合ユニーク制約で、逆の組み合わせも含めて制約をかけたい

suica_versa

総合スコア7

Ruby on Rails 5

Ruby on Rails 5は、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

PostgreSQL

PostgreSQLはオープンソースのオブジェクトリレーショナルデータベース管理システムです。 Oracle Databaseで使われるPL/SQLを参考に実装されたビルトイン言語で、Windows、 Mac、Linux、UNIX、MSなどいくつものプラットフォームに対応しています。

SQL

SQL(Structured Query Language)は、リレーショナルデータベース管理システム (RDBMS)のデータベース言語です。大きく分けて、データ定義言語(DDL)、データ操作言語(DML)、データ制御言語(DCL)の3つで構成されており、プログラム上でSQL文を生成して、RDBMSに命令を出し、RDBに必要なデータを格納できます。また、格納したデータを引き出すことも可能です。

0グッド

0クリップ

投稿2018/09/25 02:00

前提・実現したいこと

現在制作中のサービスで、友人をサービスに招待することでインセンティブを渡す
招待機能をつけたいと思っております。Dropboxのように、n人招待するとnGBの容量プレゼントのような機能を想定しています。

招待したと判断する方法は二種類で、

  • 各ユーザーごとに発行したTokenを持つ会員登録ページから登録した際
  • 会員登録後にTokenを設定ページから手動で入力した際

で想定しています。

開発環境はRails5+PostgreSQLです。
ユーザーが複数のクラス存在するためpolymorphicを使って招待関係を
以下のようなテーブルで保存しています。

Invitation
inviter_id(招待者)integer
inviter_typestring
invitee_id(被招待者)integer
invitee_typestring

発生している問題

重複して招待できないようにするため、

  • 同じ人を複数回招待できないようにする
  • お互いを招待できないようにする(User1->User2を招待したら、User2->User1にはもう招待できない)

となるようなユニーク制約をDB上に持たせたいと思っております。

この際、複合ユニーク制約を書けてUser1->User2の組み合わせがユニークになるように制約をかける方法はわかるのですが、
User2->User1も含めてユニークになるように制約を掛ける方法がわかりません。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答4

0

自分で利用したことが無いので紹介までなのですが、PostgreSQLには排他制約、除外制約というものがあります。
式に対して等価を否定できるので、利用できればやりたいことはできるかと。

PostgreSQL 9.6.5文書 CREATE TABLE

EXCLUDE句は排他制約を定義し、任意の2行について指定した列(複数可)または式(複数可)を指定した演算子(複数可)を使用して比較した場合、比較結果のすべてがTRUEを返さないことを保証します。 指定した演算子のすべてが等価性を試験するものであれば、これはUNIQUE制約と同じですが、通常の一意性制約のほうが高速です。 しかし、排他制約では単純な等価性よりも一般的な制約を指定することができます。

投稿2018/09/25 13:10

Satsuki_2981

総合スコア37

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

postgreはいまいちわからないのですが例えばmysqlなら
triggerで処理を弾くとかでしょうかね

SQL

1create table tbl1(id int primary key,uid1 int not null,uid2 int not null); 2create table tbl2(uid varchar(10) not null unique);
  • trigger

SQL

1drop trigger if exists trg_a ; 2delimiter // 3create trigger trg_a before insert on tbl1 4for each row begin 5insert into tbl2 values(concat(least(new.uid1,new.uid2),'_',greatest(new.uid1,new.uid2))); 6end; 7// 8delimiter ;
  • データ投入

SQL

1insert ignore into tbl1 values(1,100,101); // OK 2insert ignore into tbl1 values(2,100,101); // NG 3insert ignore into tbl1 values(3,101,100); // NG 4insert ignore into tbl1 values(4,100,102); // OK 5

※ただしtriggerで処理する場合、updateとdeleteの処理も用意しておかないと
整合性が保てません

投稿2018/09/25 05:59

yambejp

総合スコア114572

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

カラムを1つ追加して、招待者と被招待者を連結した項目(String)を保持するようにして、そこにユニーク制約をつければどうでしょうか
連結するルールは”IDの小さいもの:IDの大きいもの”のように格納すれば、一意になるのでは?

投稿2018/09/25 04:04

momon-ga

総合スコア4820

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

suica_versa

2018/09/26 01:55

確かに、カラムの持たせ方ならいけますね!ありがとうございます!
guest

0

ベストアンサー

DBMSには項目の組み合わせという概念はありません。順列のみです。
ですので、自前で制約を作るしか無いと思います。
例えば、以下のようなインデックスをユニーク属性で作成します。

SQL

1create unique index Invitation_unique on Invitation( 2 least(inviter_id, invitee_id), greatest(inviter_id, invitee_id) 3);

若しくは、テーブル構造を変更し、IDの小さいものを最初に登録というルールを持たせた上で、そのIDが招待者なのか被招待者なのかの識別を持たせる、というようなことが考えられます。

投稿2018/09/25 02:24

編集2018/09/26 03:48
sazi

総合スコア25138

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

suica_versa

2018/09/26 01:55

なるほど、そもそものDBの概念としてないんですね。 カラムの持たせ方で工夫することにします!ありがとうございます。
sazi

2018/09/26 03:44

一応、現状のテーブル構造でのインデックスの例を追記しました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問