列のある「ユーザー」テーブルがありますuser_email
、user_company_id
およびuser_status
。 user_status
列は、値が「1」または「0」の列挙型で、ユーザーがactiveまたはであることを表します非アクティブ。 oneunique、activeのユーザーのメールのみを許可するように、これらの3つの列に一意の制約を適用する方法はありますか?特定の会社ですが、非アクティブなメールの重複したエントリはいくつありますか?
例:次のエントリを持つ「ユーザー」テーブルを考えます
CREATE TABLE users(
user_id BIGINT(10) PRIMARY KEY AUTO_INCREMENT,
user_email VARCHAR(255) NOT NULL,
user_companyid BIGINT(10) NOT NULL,
user_status enum('1', '0'))
INSERT INTO users(user_id, user_email, user_companyid, user_status)
VALUES (1,'[email protected]','555','1');
INSERT INTO users(user_id, user_email, user_companyid, user_status)
VALUES (2,'[email protected]','555','1');
INSERT INTO users(user_id, user_email, user_companyid, user_status)
VALUES (3,'[email protected]','777','1');
SELECT * FROM users;
user_id | user_email | user_companyid | user_status
------: | :-------------- | -------------: | :----------
1 | [email protected] | 555 | 1
2 | [email protected] | 555 | 1
3 | [email protected] | 777 | 1
特定の会社の既存のアクティブなメールを2回追加することはできません。以下は失敗するはずです:
INSERT INTO users(user_id, user_email, user_companyid, user_status)
VALUES (4,'[email protected]','555','1');
アクティブユーザーのいずれかのステータスを「0」(非アクティブ)に更新すると、以前のメールステータスが非アクティブであるため、同じメールを再度挿入できるはずです。以下は成功するはずです:
UPDATE users SET user_status = '0' WHERE user_id = 1;
INSERT INTO users(user_id, user_email, user_companyid, user_status)
VALUES (4,'[email protected]','555','1');
user_id | user_email | user_companyid | user_status
------: | :-------------- | -------------: | :----------
1 | [email protected] | 555 | 0
2 | [email protected] | 555 | 1
3 | [email protected] | 777 | 1
4 | [email protected] | 555 | 1
また、制約により、非アクティブなユーザーの電子メールの重複エントリが許可されます。これも成功するはずです:
UPDATE users SET user_status = '0' WHERE user_id = 4;
SELECT * FROM users;
user_id | user_email | user_companyid | user_status
------: | :-------------- | -------------: | :----------
1 | [email protected] | 555 | 0
2 | [email protected] | 555 | 1
3 | [email protected] | 777 | 1
4 | [email protected] | 555 | 0
コメントで言ったように、ヨイはBEFORE INSERTトリガーを作成していません
CREATE TABLE users( user_id BIGINT(10) PRIMARY KEY AUTO_INCREMENT, user_email VARCHAR(255) NOT NULL, user_companyid BIGINT(10) NOT NULL, user_status enum('1', '0'))
✓
INSERT INTO users(user_id, user_email, user_companyid, user_status) VALUES (1,'[email protected]','555','1'); INSERT INTO users(user_id, user_email, user_companyid, user_status) VALUES (2,'[email protected]','555','1'); INSERT INTO users(user_id, user_email, user_companyid, user_status) VALUES (3,'[email protected]','777','1');
✓ ✓ ✓
SELECT * FROM users;
user_id | user_email | user_companyid | user_status ------:| :----------- -------------:| :---------- 1 | [email protected] | 555 | 1 2 | [email protected] | 555 | 1 3 | [email protected] | 777 | 1
CREATE TRIGGER users_before_insert BEFORE INSERT ON users FOR EACH ROW BEGIN DECLARE vUser varchar(50); -- Find username of person performing INSERT into table IF EXISTS(SELECT 1 FROM users WHERE user_email = NEW.user_email AND user_companyid = NEW.user_companyid AND user_status = 1) THEN signal sqlstate '45000' SET MESSAGE_TEXT = 'User already activated'; END IF; END;
✓
INSERT INTO users( user_email, user_companyid, user_status) VALUES ('[email protected]','555','1');
ユーザーはすでにアクティブ化されています
SELECT * FROM users;
user_id | user_email | user_companyid | user_status ------:| :-------------- | -------------:| :---------- 1 | [email protected] | 555 | 1 2 | [email protected] | 555 | 1 3 | [email protected] | 777 | 1
db <> fiddle ---(ここ
Auto_incrementカラムは生成されたカラムから参照できないため、これは機能しませんでしたが、便利なテクニックを示しているため、とにかく追加します。生成された列を使用するという考え方です。user_status= 0の場合、一意であることが保証されているもの(主キー)にマップされ、それ以外の場合は定数にマップされます。次に、この列をUNIQUE制約に、条件のもとで一意である必要がある列と一緒に含めることができます。
CREATE TABLE users
( user_id BIGINT PRIMARY KEY -- auto_increment had to be removed
, user_email VARCHAR(255) NOT NULL
, user_companyid BIGINT NOT NULL
, user_status enum('1', '0')
, gencol BIGINT GENERATED ALWAYS as
( CASE WHEN user_status = 1
THEN -1
ELSE user_id
END
) NOT NULL
);
ALTER TABLE users ADD CONSTRAINT ak1
UNIQUE (user_email, user_companyid, gencol);
INSERT INTO users(user_id, user_email, user_companyid, user_status)
VALUES (1,'[email protected]','555','1');
INSERT INTO users(user_id, user_email, user_companyid, user_status)
VALUES (2,'[email protected]','555','1');
INSERT INTO users(user_id, user_email, user_companyid, user_status)
VALUES (3,'[email protected]','777','1');
-- Fails
-- INSERT INTO users(user_id, user_email, user_companyid, user_status)
-- VALUES (4,'[email protected]','555','1');
UPDATE users SET user_status = '0' WHERE user_id = 1;
-- Succeeds
INSERT INTO users(user_id, user_email, user_companyid, user_status)
VALUES (4,'[email protected]','555','1');