happy day.
I am creating a database of movies, all movies will receive one vote for each user, valuing as it seemed the movie, "Good, good or fair" These votes of these stored in a table [movies_has_rating] that have the ID of the user who made the vote, with the type of vote, and the creation date, I need to ensure and prevent a user can participate twice in a movie, as only one vote per user is allowed, although this already I have done through PHP and MySQL queries, there is still the possibility of adding it manually from MySQL, and would also be able to establish this same default MySQL, my question is:
1) If the fields are defined [vote id] and [user_id] as primary keys, you can avoid having two evaluations of a user for the same film, example.
CREATE TABLE `user_has_rating` (
`movie_id` int UNSIGNED NOT NULL ,
`vote_id` int UNSIGNED NOT NULL ,
`user_id` int UNSIGNED NOT NULL ,
`create_at` datetime NOT NULL ,
PRIMARY KEY (`vote_id`, `user_id`)
)
2) It is necessary to add to the fields UNIQUE INDEX [vote id] and [user_id], when they are already defined as primary keys, which has advantages and differences using UNIQUE INDEX when we defininas primary keys.
CREATE TABLE `user_has_rating` (
`movie_id` int UNSIGNED NOT NULL ,
`vote_id` int UNSIGNED NOT NULL ,
`user_id` int UNSIGNED NOT NULL ,
`create_at` datetime NOT NULL ,
PRIMARY KEY (`vote_id`, `user_id`),
UNIQUE INDEX `vote_id` (`vote_id`) ,
UNIQUE INDEX `user_id` (`user_id`)
);
3) It is necessary to specify the type of method the index, such as "BTREE or HASH"
CREATE TABLE `user_has_rating` (
`movie_id` int UNSIGNED NOT NULL ,
`vote_id` int UNSIGNED NOT NULL ,
`user_id` int UNSIGNED NOT NULL ,
`create_at` datetime NOT NULL ,
PRIMARY KEY (`vote_id`, `user_id`),
UNIQUE INDEX `vote_id` (`vote_id`) USING BTREE ,
UNIQUE INDEX `user_id` (`user_id`) USING BTREE
);
Much appreciate your help, thank you very much!
Related
I have this table:
CREATE TABLE `executed_tests` (
`id` INTEGER AUTO_INCREMENT NOT NULL,
`user_id` INTEGER NOT NULL,
`test_id` INTEGER NOT NULL,
`start_date` DATE NOT NULL,
`completed_date` DATE,
PRIMARY KEY (`id`)
);
I want to set up an unique constraint on fields user_id and test_id, but only when conclusion_date is null. If conclusion_date is not null, the constraint doesn't apply.
So there will exist only one incomplete execution per user and test.
Something like this:
UNIQUE(`user_id`, `test_id`) WHEN (`completed_date` IS NULL)
How can I accomplish this on MySQL 5.6?
MySQL supports functional key parts since 8.0.13.
If your version is sufficiently recent you can define your index as:
UNIQUE(`user_id`, `test_id`, (IFNULL(`completed_date`, -1)))
(Demo on dbfiddle.uk)
Note that the above index will also prevent duplciate dates for completed executions. If those should be valid then a slightly modified index would work:
UNIQUE(`user_id`, `test_id`, (
CASE WHEN `completed_date` IS NOT NULL
THEN NULL
ELSE 0
END))
(Demo on dbfiddle.uk)
Although then it starts to feel a bit dirty ;)
If you have at least version 5.7 you can use a (virtual) generated column as workaround:
CREATE TABLE `executed_tests` (
`id` INTEGER AUTO_INCREMENT NOT NULL,
`user_id` INTEGER NOT NULL,
`test_id` INTEGER NOT NULL,
`start_date` DATE NOT NULL,
`completed_date` DATE,
`_helper` CHAR(11) AS (IFNULL(`completed_date`, -1)),
PRIMARY KEY (`id`),
UNIQUE(`user_id`, `test_id`, `_helper`)
);
(Demo on dbfiddle.uk)
If you are stuck on 5.6 then a combination of a regular (non-virtual) column and slightly modified INSERT statements would work:
CREATE TABLE `executed_tests` (
`id` INTEGER AUTO_INCREMENT NOT NULL,
`user_id` INTEGER NOT NULL,
`test_id` INTEGER NOT NULL,
`start_date` DATE NOT NULL,
`completed_date` DATE,
`is_open` BOOLEAN,
PRIMARY KEY (`id`),
UNIQUE(`user_id`, `test_id`, `is_open`)
);
In this case you would set is_open to true for incomplete executions and to NULL after completion, making use of the fact that two NULLs are treated as not equal.
(Demo on dbfiddle.uk)
Here is a table in MySQL 5.3.X+ db:
CREATE TABLE members` (
`id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`memberid` VARCHAR( 30 ) NOT NULL ,
`Time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ,
`firstname` VARCHAR( 50 ) NULL ,
`lastname` VARCHAR( 50 ) NULL ,
UNIQUE (memberid),
PRIMARY KEY (id)
) ENGINE = MYISAM;
Id column is never used in queries, it is just for visual convenience (so it's easy to see how the table grows). Memberid is an actual key, is unique, and memberid is used in queries to identify any member (WHERE memberid='abcde').
My question is: how to keep auto_increment, but make memberid as a primary key? Is that possible?
When I try to create this table with PRIMARY KEY (memberid), I get an error:
1075 - Incorrect table definition; there can be only one auto column and it must be defined as a key
What is the best choice (Hopefully, there is a way to keep id column so performance is good and queries identify any user by memberid, not by id), if the performance is very important (although the disk space is not)?
You can have an auto-Incrementing column that is not the PRIMARY KEY, as long as there is an index (key) on it:
CREATE TABLE members (
id int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
memberid VARCHAR( 30 ) NOT NULL ,
`time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ,
firstname VARCHAR( 50 ) NULL ,
lastname VARCHAR( 50 ) NULL ,
PRIMARY KEY (memberid) ,
KEY (id) --- or: UNIQUE KEY (id)
) ENGINE = MYISAM;
First create table without auto_increment,
CREATE TABLE `members`(
`id` int(11) NOT NULL,
`memberid` VARCHAR( 30 ) NOT NULL ,
`Time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ,
`firstname` VARCHAR( 50 ) NULL ,
`lastname` VARCHAR( 50 ) NULL
PRIMARY KEY (memberid)
) ENGINE = MYISAM;
after set id as index,
ALTER TABLE `members` ADD INDEX(`id`);
after set id as auto_increment,
ALTER TABLE `members` CHANGE `id` `id` INT(11) NOT NULL AUTO_INCREMENT;
Or
CREATE TABLE IF NOT EXISTS `members` (
`id` int(11) NOT NULL,
`memberid` VARCHAR( 30 ) NOT NULL ,
`Time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ,
`firstname` VARCHAR( 50 ) NULL ,
`lastname` VARCHAR( 50 ) NULL,
PRIMARY KEY (`memberid`),
KEY `id` (`id`)
) ENGINE=MYISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
You can make the id the primary key, and set member_id to NOT NULL UNIQUE. (Which you've done.) Columns that are NOT NULL UNIQUE can be the target of foreign key references, just like a primary key can. (I'm pretty sure that's true of all SQL platforms.)
At the conceptual level, there's no difference between PRIMARY KEY and NOT NULL UNIQUE. At the physical level, this is a MySQL issue; other SQL platforms will let you use a sequence without making it the primary key.
But if performance is really important, you should think twice about widening your table by four bytes per row for that tiny visual convenience. In addition, if you switch to INNODB in order to enforce foreign key constraints, MySQL will use your primary key in a clustered index. Since you're not using your primary key, I imagine that could hurt performance.
I think i understand what the reason of your error.
First you click auto AUTO INCREMENT field then select it as a primary key.
The Right way is First You have to select it as a primary key then you
have to click auto AUTO INCREMENT field.
Very easy.
Thanks
For the above issue, first of all if suppose tables contains more than 1 primary key then first remove all those primary keys and add first AUTO INCREMENT field as primary key then add another required primary keys which is removed earlier. Set AUTO INCREMENT option for required field from the option area.
Identified this solution while reading this thread. Figured id post this for the next guy possibly.
When dealing with Laravel migration file from a package, I Ran into this issue.
My old value was
$table->increments('id');
My new
$table->integer('id')->autoIncrement();
I need a table to store text every week for each user.
So I thought two alternatives:
1) Using composite primary key:
CREATE TABLE `WeeklyTxt` (
`Year` YEAR(4) NOT NULL ,
`Week` ENUM('1','2','3','4', ... ,'51','52','53') NOT NULL ,
`UserId` BIGINT NOT NULL ,
`WeekTxt` TEXT NOT NULL,
PRIMARY KEY (`Year`, `Week`, `UserId`)
) ENGINE = InnoDB;
2) Using autoincrement primary key
CREATE TABLE `WeeklyTxt_2` (
`WeekTxtId` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
`Year` YEAR(4) NOT NULL ,
`Week` ENUM('1','2','3','4', ... ,'51','52','53') NOT NULL ,
`UserId` BIGINT NOT NULL ,
`WeekTxt` TEXT NOT NULL
) ENGINE = InnoDB;
I can't figure out what could be the better choice (and why)
It depends of the search in the table that you will usually do!
Tipically I would use a Simple PRIMARY KEY, and I will add another KEY like your KEY: (Year, Week, UserId)
I'm sorry if the title isn't exactly.. useful, but I wasn't sure how to explain my issue in a title.
So basically, I want to create a table like that :
reservation
day
room
id_client
[other_stuff]
For a given day+room, you can get the id_client + everything else. And also for a given id_client + day you can get the room + other stuff.
I don't exactly understand how am I supposed to say that the compound day+room must be unique AND the compound day+id_client must also be unique. I really need both of those constraint in my database.
Anyone has an idea ?
Thanks.
Define one combination an PRIMARY KEY and the other as UNIQUE key:
CREATE TABLE reservation
( day
, room
, id_client
, [other_stuff]
, PRIMARY KEY (day, room)
, UNIQUE KEY (id_client, day)
) ;
or the other way around:
CREATE TABLE reservation
( day
, room
, id_client
, [other_stuff]
, PRIMARY KEY (id_client, day)
, UNIQUE KEY (day, room)
) ;
Or, if you already have another Primary Key, make them both unique:
CREATE TABLE reservation
( reservation_id
, day
, room
, id_client
, [other_stuff]
, PRIMARY KEY (reservation_id)
, UNIQUE KEY (id_client, day)
, UNIQUE KEY (day, room)
) ;
-- in MySQL
drop database if exists mydatabase;
create database mydatabase;
use mydatabase;
drop table if exists client;
create table client
(
id int unsigned not null auto_increment,
name varchar(45) not null,
primary key (id)
)engine=InnoDB default charset=utf8;
drop table if exists room;
create table room
(
id int unsigned not null auto_increment,
label varchar(45) not null,
primary key (id)
)engine=InnoDB default charset=utf8;
drop table if exists reservation;
create table reservation
(
id int unsigned not null auto_increment,
id_room int unsigned,
id_client int unsigned,
day date,
unique(day, id_room),
unique(day, id_client),
foreign key (id_room) references room(id),
foreign key (id_client) references client(id),
primary key (id)
)engine=InnoDB default charset=utf8;
There are two ways of looking at this... are the unique constraints you mention mutually exclusive? Meaning, can one exist without the other?
Logic dictates that a room can be booked to one day at a time, regardless of client. Unless multiple clients can share the same room. So I will give you two alternatives.
# If room can be booked to multiple clients
CREATE TABLE `reservation` (
`id` int(11) unsigned not null auto_increment,
`day` varchar(25) not null,
`room` int(5) unsigned not null,
`id_client` int(11) unsigned not null,
PRIMARY KEY (`id`),
UNIQUE KEY (`room`, `day`),
UNIQUE KEY (`room`, `id_client`),
)ENGINE=InnoDB DEFAULT CHARSET=utf8;
# Room can only be booked to one client for a given day
CREATE TABLE `reservation` (
`id` int(11) unsigned not null auto_increment,
`day` varchar(25) not null,
`room` int(5) unsigned not null,
`id_client` int(11) unsigned not null,
PRIMARY KEY (`id`),
UNIQUE KEY (`room`, `day`)
)ENGINE=InnoDB DEFAULT CHARSET=utf8;
Also, I would use a separate primary key column, otherwise your updates will be more complex, for example:
UPDATE `reservation` SET `other_stuff` = 'some value' WHERE `day` = 'Friday' AND `room` = 123;
# Vs
UPDATE `reservation` SET `other_stuff` = 'some value' WHERE `id` = 1;
Here is a table in MySQL 5.3.X+ db:
CREATE TABLE members` (
`id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`memberid` VARCHAR( 30 ) NOT NULL ,
`Time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ,
`firstname` VARCHAR( 50 ) NULL ,
`lastname` VARCHAR( 50 ) NULL ,
UNIQUE (memberid),
PRIMARY KEY (id)
) ENGINE = MYISAM;
Id column is never used in queries, it is just for visual convenience (so it's easy to see how the table grows). Memberid is an actual key, is unique, and memberid is used in queries to identify any member (WHERE memberid='abcde').
My question is: how to keep auto_increment, but make memberid as a primary key? Is that possible?
When I try to create this table with PRIMARY KEY (memberid), I get an error:
1075 - Incorrect table definition; there can be only one auto column and it must be defined as a key
What is the best choice (Hopefully, there is a way to keep id column so performance is good and queries identify any user by memberid, not by id), if the performance is very important (although the disk space is not)?
You can have an auto-Incrementing column that is not the PRIMARY KEY, as long as there is an index (key) on it:
CREATE TABLE members (
id int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
memberid VARCHAR( 30 ) NOT NULL ,
`time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ,
firstname VARCHAR( 50 ) NULL ,
lastname VARCHAR( 50 ) NULL ,
PRIMARY KEY (memberid) ,
KEY (id) --- or: UNIQUE KEY (id)
) ENGINE = MYISAM;
First create table without auto_increment,
CREATE TABLE `members`(
`id` int(11) NOT NULL,
`memberid` VARCHAR( 30 ) NOT NULL ,
`Time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ,
`firstname` VARCHAR( 50 ) NULL ,
`lastname` VARCHAR( 50 ) NULL
PRIMARY KEY (memberid)
) ENGINE = MYISAM;
after set id as index,
ALTER TABLE `members` ADD INDEX(`id`);
after set id as auto_increment,
ALTER TABLE `members` CHANGE `id` `id` INT(11) NOT NULL AUTO_INCREMENT;
Or
CREATE TABLE IF NOT EXISTS `members` (
`id` int(11) NOT NULL,
`memberid` VARCHAR( 30 ) NOT NULL ,
`Time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ,
`firstname` VARCHAR( 50 ) NULL ,
`lastname` VARCHAR( 50 ) NULL,
PRIMARY KEY (`memberid`),
KEY `id` (`id`)
) ENGINE=MYISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
You can make the id the primary key, and set member_id to NOT NULL UNIQUE. (Which you've done.) Columns that are NOT NULL UNIQUE can be the target of foreign key references, just like a primary key can. (I'm pretty sure that's true of all SQL platforms.)
At the conceptual level, there's no difference between PRIMARY KEY and NOT NULL UNIQUE. At the physical level, this is a MySQL issue; other SQL platforms will let you use a sequence without making it the primary key.
But if performance is really important, you should think twice about widening your table by four bytes per row for that tiny visual convenience. In addition, if you switch to INNODB in order to enforce foreign key constraints, MySQL will use your primary key in a clustered index. Since you're not using your primary key, I imagine that could hurt performance.
I think i understand what the reason of your error.
First you click auto AUTO INCREMENT field then select it as a primary key.
The Right way is First You have to select it as a primary key then you
have to click auto AUTO INCREMENT field.
Very easy.
Thanks
For the above issue, first of all if suppose tables contains more than 1 primary key then first remove all those primary keys and add first AUTO INCREMENT field as primary key then add another required primary keys which is removed earlier. Set AUTO INCREMENT option for required field from the option area.
Identified this solution while reading this thread. Figured id post this for the next guy possibly.
When dealing with Laravel migration file from a package, I Ran into this issue.
My old value was
$table->increments('id');
My new
$table->integer('id')->autoIncrement();