mysql how to use two field as primary key and unique - mysql

In MySQL database I have the data
create table student(user_id int(20) unsigned NOT NULL AUTO_INCREMENT,
name varchar(20),
email varchar(20),
primary key(user_id,email));
I want to use user_id and email field should be unique value.
I also add
alter table student add unique unique_index (user_id,email);
but still it accepts all the entry
mysql> insert into student (name, email) values ("a", "aa", "aa");
Query OK, 1 row affected (0.06 sec)
mysql> insert into student (name, email) values ("a", "aa", "aa");
Query OK, 1 row affected (0.06 sec)
select * from student;
+---------+------+-------+
| user_id | name | email |
+---------+------+-------+
| 1 | a | aa |
| 2 | a | aa |
+---------+------+-------+
2 rows in set (0.00 sec)
how can I make that fields(id and email) as unique?

you can use like these. Here every unique index name should be different.
CREATE TABLE student(user_id INT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
NAME VARCHAR(20),
email VARCHAR(20),
PRIMARY KEY(user_id,email));
unique index creation.
ALTER TABLE student ADD UNIQUE unique_index1 (user_id);
ALTER TABLE student ADD UNIQUE unique_index2 (email);
Inserting data:
INSERT INTO student (`name`, email) VALUES ("a", "aa");
Execute below SQL it gives error.
INSERT INTO student (`name`, email) VALUES ("a", "aa");
Thank you.

As my understandind of your requirement is correct, you have to add to unique indexes:
alter table student add unique unique_index (user_id);
alter table student add unique unique_index_email (email);
Your statement will create a index where the combination of user_id and email is unique!

Related

MySQL constraint to ensure data integrity between two tables (1-n cardinality)

I made a minimal example to describe my problem using the concept of player using items in a game (which makes my problem easier to understand).
My problematic is the following. Let's say I have to store items and the player holding them in my database.
I didn't show it on the image but a player could hold no item but it's really important for my problem.
I translated that into :
Which gives the two following tables (with PK_ and #FK) :
In my example I can then fill them as such :
By doing :
Now, I want any player to have a "favorite" item, so I want to add a foreign key #item_id in the table Player but I want to make sure this new value refers to an item being hold by the right player in the Item table. How can I add a (check?) constraint to my table declarations so that condition is always true to ensure data integrity between my two tables? I don't think I can solve this by creating a third table since it's still a 1n cardinality. Also I don't want to ALTER the table I want to CREATE, since my database is not yet to be deployed.
You can add a third table which links the player and item table for the favorite item for each player (if you don't want a cycle reference between player and item). There are two restrictions to solve:
A player must own the item, they want to have as a favorite.
A player can have only one favorite item.
The first point can be solved with a multi-column foreign key. The table item needs an index for the playerId and the id of the item. Then your new table for the favorite items can reference this index as a foreign key. The inclusion of the playerId in the foreign key ensures that the item isn't "moved" to a different player while it is marked as favorite. The queries will look like this:
CREATE TABLE item(
id INT AUTO_INCREMENT PRIMARY KEY NOT NULL,
playerId INT NOT NULL,
INDEX item_id_and_playerId (playerId, id)
);
CREATE TABLE favItem(
id INT AUTO_INCREMENT PRIMARY KEY NOT NULL,
playerId INT NOT NULL,
itemId INT NOT NULL,
FOREIGN KEY favItem_FQ_id_and_playerId (playerId, itemId) REFERENCES item(playerId, id)
);
The second point can be solved by a simple UNIQUE constraint on the playerId column of the new favorite items table. That way only one item can be marked as favorite. We adjust the CREATE TABLE query for the favItem table as follow:
CREATE TABLE favItem(
id INT AUTO_INCREMENT PRIMARY KEY NOT NULL,
playerId INT NOT NULL,
itemId INT NOT NULL,
FOREIGN KEY favItem_FQ_id_and_playerId (playerId, itemId) REFERENCES item(playerId, id),
CONSTRAINT favItem_UQ_playerId UNIQUE (playerId)
);
See the following queries how they work:
mysql> SELECT * FROM player;
+----+
| id |
+----+
| 1 |
| 2 |
| 3 |
+----+
3 rows in set (0.00 sec)
mysql> SELECT * FROM item;
+----+----------+
| id | playerId |
+----+----------+
| 1 | 1 |
| 2 | 1 |
| 3 | 2 |
| 4 | 3 |
| 5 | 3 |
| 6 | 3 |
+----+----------+
6 rows in set (0.00 sec)
mysql> INSERT INTO favItem(playerId, itemId) VALUES (1, 2);
Query OK, 1 row affected (0.01 sec)
mysql> INSERT INTO favItem(playerId, itemId) VALUES (3, 2);
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails
(`test`.`favItem`, CONSTRAINT `favItem_ibfk_1` FOREIGN KEY
(`playerId`, `itemId`) REFERENCES `item` (`playerId`, `id`))
mysql> INSERT INTO favItem(playerId, itemId) VALUES (1, 1);
ERROR 1062 (23000): Duplicate entry '1' for key 'favItem.favItem_UQ_playerId'
The first row can be added without problem. However, the second row can't be added because the player with the id playerId=3 does not "own" the item with the id itemId=2. The third row can't be added either because the player with the id playerId=1 cannot mark the item with the id itemId=1 (which he owns) as a favorite because of the UNIQUE constraint on playerId.
You can add an isFavorite column in the Item table. It's value is either NULL or a predefined value, like a ENUM value. Then you can add a UNIQUE constraint over the two columns playerId and isFavorite. That way, a player can have only one item as favorite, since multiple rows with the same playerId and isFavorite value would result in a unique constraint error. The table can look like this:
CREATE TABLE items(
id INT AUTO_INCREMENT PRIMARY KEY NOT NULL,
playerId INT NOT NULL,
isFavorite ENUM('FAV') NULL,
CONSTRAINT items_UQ_fav UNIQUE (PlayerId, isFavorite)
);
Check the following queries how a new row would validate the unique constraint:
mysql> INSERT INTO
items(playerId, isFavorite)
VALUES
(4, NULL), (7, NULL), (7, 'FAV'), (5, 'FAV');
Query OK, 4 rows affected (0.02 sec)
Records: 4 Duplicates: 0 Warnings: 0
mysql> SELECT * FROM items;
+----+----------+------------+
| id | playerId | isFavorite |
+----+----------+------------+
| 1 | 4 | NULL |
| 4 | 5 | FAV |
| 2 | 7 | NULL |
| 3 | 7 | FAV |
+----+----------+------------+
4 rows in set (0.00 sec)
mysql> INSERT INTO items(playerId, isFavorite) VALUES (5, 'FAV');
ERROR 1062 (23000): Duplicate entry '5-FAV' for key 'items.items_UQ_fav'

What is the best way to generate primary key automatically?

I want to generate my primary key automatically in MySQL data table. But I want it to be a character string though in sequence.
Example:
user_id (Primary Key)
USER000001
USER000002
USER000003
USER000004 ....and so on..
By separate table for sequencing and a trigger, you can generate PK automatically with your format.
Tables
CREATE TABLE tableName_seq
(
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY
);
CREATE TABLE tableName
(
id VARCHAR(10) NOT NULL PRIMARY KEY DEFAULT '0', name VARCHAR(30)
);
Now the trigger
DELIMITER $$
CREATE TRIGGER tg_table_insert
BEFORE INSERT ON tableName
FOR EACH ROW
BEGIN
INSERT INTO tableName_seq VALUES (NULL);
SET NEW.id = CONCAT('USER', LPAD(LAST_INSERT_ID(), 6, '0'));
END$$
DELIMITER ;
Then you just insert rows to table
INSERT INTO tableName (name)
VALUES ('Jhon'), ('Mark');
And you'll have
| ID | NAME |
------------------
| USER000001 | Jhon |
| USER000002 | Mark |

Inserting value in one table for all the rows in another table

I want to write a sql script, which inserts into table some value for all the ids in some other table.
create table person
(
id int(11) not null auto_increment,
name varchar(255),
primary key (id)
);
insert into person
values (null, 'John'), (null, 'Sam');
select * from person;
id | name
----------
1 | John
2 | Sam
create table phone_details
(
id int(11) not null auto_increment,
person_id int(11),
phone int(11),
constraint person_ibfk_1 foreign key (person_id) references person (id) on delete no action,
primary key (id)
);
Now, in the phone_details table, I want the following :
id | person_id | phone
----------------------------
1 | 1 | 9999999999
2 | 2 | 9999999999
How do I do that ? Currently, I am using Java to write this one time script, but I think there must be a way of doing this in sql.
You can use INSERT INTO ... SELECT syntax:
INSERT INTO phone_details(person_id,phone)
SELECT id, 99999999
FROM person;
Consider storing phone number as VARCHAR.
SqlFiddleDemo

How to make SQL Server 2008 table primary key auto increment with some prefix

The given query is in mysql format. I want same query in SQL Server 2008.
CREATE TABLE table1_seq
(
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY
);
CREATE TABLE table1
(
id VARCHAR(7) NOT NULL PRIMARY KEY DEFAULT '0', name VARCHAR(30)
);
Now the trigger
DELIMITER $$
CREATE TRIGGER tg_table1_insert
BEFORE INSERT ON table1
FOR EACH ROW
BEGIN
INSERT INTO table1_seq VALUES (NULL);
SET NEW.id = CONCAT('LHPL', LPAD(LAST_INSERT_ID(), 3, '0'));
END$$
DELIMITER ;
Then you just insert rows to table1
INSERT INTO Table1 (name)
VALUES ('Jhon'), ('Mark');
And you'll have
| ID | NAME |
------------------
| LHPL001 | Jhon |
| LHPL002 | Mark |
This may answer your question
-- create table with 'ABCD' as prefix, combining with identity column Id
CREATE TABLE dbo.Persons
(
Id int IDENTITY (1,1) NOT NULL
,PersonId AS ('ABCD' + CONVERT(varchar(20), Id)) PERSISTED NOT NULL PRIMARY KEY
,Name varchar(100)
);
GO
-- Do not specify calculated column when insert values into the table
INSERT INTO dbo.Persons (Name)
VALUES ('Person1'), ('Person2'), ('Person3');
GO
-- Display the records from the table
SELECT PersonId, Name
FROM dbo.Persons;
GO
This approach does not require to create a separate table and trigger, therefore efficient.
Hope this helps.

Ignore insert if exist in table in mysql?

I have 6 columns in my table:
Id | Name | Mail id | Gender | Contact Number | father name
while inserting a data into table i wanted to check condition like if Name,mailid,contact number already exists then insert should not happen else record should be inserted.
Can any one suggest how to check the condition while inserting a record.
IF NOT EXISTS (SELECT * FROM Table_Name WHERE Condition you are checking)
BEGIN
INSERT INTO ............. ---<----- Your Insert Statement.....
END
You can define an index on multiple columns, e.g.:
CREATE UNIQUE INDEX arbitrary_index_name ON table_name (Name, mailid, contactnumber);
I also faced similar situation, you can do this by adding unique constraint to your table and using 'insert ignore' statement to add data.
Create table statement:
CREATE TABLE Student (
Id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(50),
Mailid VARCHAR(50),
Gender CHAR,
contactnumber BIGINT,
fathername VARCHAR(50),
UNIQUE(NAME,Mailid,contactnumber));
Insert Ignore statement:
INSERT IGNORE INTO student(NAME, Mailid,Gender,contactnumber,fathername) VALUES('Shekhar', 's#s.com', 'M', 987654321, 'Joshi');