Constraint on the same row - mysql

If there is possible insert of the same row in table I want to ignore this one. Here the table with foreign key game_id and 2 fields step_num and cell, they could differ and should differ. Cell should be 0-8 and always different for game_id. Step_num the same, but 1-9. But I can't set unique, because the could be the same, but in different game_id's.
Here is part of the script:
create table games(
id int not null auto_increment primary key,
name varchar(255) not null unique ,
status varchar(255) not null,
createDate DATETIME
);
create table steps(
game_id int not null ,
step_num int not null,
cell int not null,
constraint cell_unique on games(id),
constraint chk_number check(step_number > 0 and step_number < 10),
constraint fk_game foreign key (game_id) references games(id) on delete cascade,
constraint chk_cell check(cell >= 0 and cell <= 8)
);
INSERT IGNORE didn't worked adn INSERT ON DUPLICATE KEY I think not what I need. If I try Insert (2, 2, 2) several times, it should ignore. I prevent this actions on the back-end side, but want, that db was correct and automatically prevent from similar actions.
What are the ways to do it correctly?

You have 2 options:
Define composite primary key using ( game_id, step_num, cell ). This restricts repeated row data like 2, 2, 2.
Define a before insert trigger that checks duplicates and
to restrict, updates the same row with same values, affecting no rows.
And as per my knowledge check constraints have no effect in MySQL.

Related

MySQL Trigger Code to enter statement based on another value

EDIT **********
I couldn't get the below code to work so I have tried to run it in the diagram tool on Workbench. This is my code
CREATE DEFINER = CURRENT_USER TRIGGER `MeasureUp_Data`.`bmd_results_BEFORE_INSERT` BEFORE INSERT ON `bmd_l_arm` FOR EACH ROW
BEGIN
INSERT INTO bmd_results VALUES ( new.bmd_l_arm_typ
CASE new.l_arm_tscore
WHEN < -2.5 THEN 'osteoporosis'
WHEN > -2.4 < -1.0 THEN 'osteopenia'
WHEN > -1.0 THEN 'normal'
ELSE NULL
END);
END
Im getting red crosses all though the code. Basically the values will be automatically entered into data.bmd_l_arm and I want the field in data.bmd_results labelled bmd_l_arm_typ to have the text entry based on the numerical result pushed into l_arm_tscore
Thanks for you ongoing help!
I am very new to the coding game and have been creating a Db on MySQL to add some value to my company. I have created the DB schema and want to have a field in one of my table insert a value based on a entry which comes into another table. Basically this is for a medical reporting database and I would like the diagnosis to appear in text on in as a field entry.
This is the table which I would like the values to appear, more specially i would like the column (for example) bmd_sp_typ to inset a VARCHAR (I will specify the result) based on a numerical result in a different table.
CREATE TABLE IF NOT EXISTS `MeasureUp_Data`.`bmd_results` (
`access_no` INT NOT NULL,
`bmd_sp_typ` VARCHAR(45) NULL,
PRIMARY KEY (`access_no`),
INDEX `pat_id_FK_idx` (`pat_id` ASC),
INDEX `fk_site_bmd_site_idx` (`site_id` ASC),
UNIQUE INDEX `pat_id_UNIQUE` (`pat_id` ASC),
UNIQUE INDEX `site_id_UNIQUE` (`site_id` ASC),
UNIQUE INDEX `access_no_UNIQUE` (`access_no` ASC),
CONSTRAINT `fk_demo_results_id`
FOREIGN KEY (`pat_id`)
REFERENCES `MeasureUp_Data`.`patient_demo` (`pat_id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `fk_site_bmd_site`
FOREIGN KEY (`site_id`)
REFERENCES `MeasureUp_Data`.`site_cont` (`site_id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB
The table where the numerical result will be found is below. Basically is the value for spine_total_bmd is X then Y will be inserted into bmd_sp_type, alternatively, if spine_total_bmd is A then B will be inserted.
CREATE TABLE IF NOT EXISTS `MeasureUp_Data`.`bmd_spine` (
`access_no` INT NOT NULL,
`spine_total_bmd` INT NULL,
`spine_total_tscore` INT NULL,
`spine_total_zscore` INT NULL,
`spine_total_peakref` INT NULL,
`spine_total_agemat` INT NULL,
PRIMARY KEY (`access_no`),
CONSTRAINT `fk_bmd_spine_access`
FOREIGN KEY (`access_no`)
REFERENCES `MeasureUp_Data`.`bmd_results` (`access_no`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB
Any help for this coding noob will be greatly appreciated.
You can write an INSERT trigger -
CREATE TRIGGER trigger
BEFORE INSERT
ON bmd_spine
FOR EACH ROW
BEGIN
INSERT INTO bmd_results VALUES (
new.access_no,
CASE new.spine_total_bmd
WHEN 1 THEN 'y'
WHEN 2 THEN 'b'
ELSE NULL
END);
END
Also, you can just select data from the table and change values on the fly, and do not store duplicated values. Here it is an example -
SELECT
access_no,
CASE spine_total_bmd
WHEN 1 THEN 'y'
WHEN 2 THEN 'b'
ELSE NULL
END
FROM
bmd_spine;

SQL compound unique key with null

This is how I create the table:
CREATE TABLE IF NOT EXISTS division (
DIV_ID INTEGER PRIMARY KEY ,
DIV_CODE VARCHAR(10) ,
DIV_NAME VARCHAR(20) ,
GR_ID INTEGER ,
UNIQUE (DIV_CODE, DIV_NAME, GR_ID) ,
CONSTRAINT FK1 FOREIGN KEY (GR_ID) REFERENCES grade(GR_ID) )
If a row exists where DIV_CODE="1", DIV_NAME="1" and GR_ID=1, and I try inserting another row with values "1", "1" and 1, then I get a SQL integrity error, which is expected.
If a row exists where DIV_CODE="1", DIV_NAME="1" and GR_ID=null, and I try inserting another row with vales "1", "1" and null, then the new row is inserted. I now have 2 rows with the same values for each column. Can I setup the table differently to get a similar integrity error for this scenario?
Thanks
EDIT
removed NOT NULL from GR_ID definition.

MySql replace with multiple primary keys

I have a table which has three primary keys and references three other tables
Here is the table scheema:
CREATE TABLE IF NOT EXISTS training_matrix_reference(
employee INT NOT NULL,
training_matrix INT NOT NULL,
training_record INT UNSIGNED NOT NULL,
PRIMARY KEY (employee, training_matrix,training_record),
FOREIGN KEY (employee) REFERENCES employees(id),
FOREIGN KEY (training_matrix) REFERENCES training_matrix_courses(id),
FOREIGN KEY (training_record) REFERENCES training_records(m_id)
)
I'm trying to craft a REPLACE statement which updates the training_record column or training_matrix column or both columns or creates a new row if not exists, but I also need to check that the employee belongs to the same company.
Here's what I tried so far:
REPLACE INTO `training_matrix_reference`
( employee, training_matrix, training_record ) (
SELECT id, '5', '100'
FROM employees
WHERE id =22
AND company =64
)
So my theory was that this should have replaced the first row in the table, updating training_record to 100 but in fact it actually created a new row:
22 | 5 | 100
My guess is that this happened because training_record is a primary key?
But I'm not sure that removing the primary keys/references is the right way to go as this table is used as a many to many table in other queries.
Effectively what I'm trying to do is:
REPLACE INTO `training_matrix_reference`
( employee, training_matrix, training_record )
VALUES
(22,33,18)
WHERE
employee = 22
and training_matrix = 5
and training_record = 2189
But obviously a replace statement doesn't have a where clause.
I did check out these similar questions:
MySQL REPLACE INTO on multiple keys?
mysql REPLACE query with multiple primary keys
But unfortunately MySql is not my strong suit and I could really use some help.
I hope I explained things clearly, Thanks
The PRIMARY KEY of the training_matrix_reference table is the combination of three columns. The table doesn't have multiple primary keys, it has a single PRIMARY KEY.
The REPLACE syntax you have is equivalent to performing:
DELETE FROM training_matrix_reference
WHERE employee = 22
AND training_matrix = 5
AND training_record = 100
;
INSERT INTO training_matrix_reference (employee, training_matrix, training_record)
VALUES (22, 5, 100);
;
The DELETE action only removes rows where the entire primary key is matched. Given the information you provided, we'd expect a row to be added to the table.
Did you have a question?
you should make a joining table between (employee, training_matrix_reference)
or dispense at lest one relation

MySQL foreign keys doesn't cause child table to populate

I'm trying to create relationships in MySQL using forein keys. Everytime I successfully create the forien key, but when I describe the table, the key is considered "MUL". After inserting some records into the parent table, I get null values in the child. I've been researching this for hours and have come up empty handed. I even checked the innodb status and have no foreign key error reports. I'm not entirely sure why I'm getting null values, but I'm assuming its because of the "MUL" key value. Can someone confirm this and try and help me out?
create table employee
( id int
, first varchar(128)
, last varchar(128)
, primary key(id)
) engine=innodb;
create table borrow
(ref auto_increment
, empID int
, book varchar(128)
, primary key(ref)
) engine=innodb;
alter table borrow add constraint fk_borrow
foreign key (empID) references employee(id);
insert into borrow (empID, book) values (1,'mike');
The 'MUL' just means that it's not a unique index (i.e. duplicate values are allowed for the KEY). (If it were a unique index, the Key column would show 'UNI'). The FOREIGN KEY constraint doesn't have anything to do with the uniqueness of the foreign key column... it normally is non-unique... a parent can usually have zero, one or more children.
The FOREIGN KEY constraint does not disallow NULL values in the child table. Only a NOT NULL constraint (or a trigger) will do that for you. It's perfectly reasonable for a row in a child table to be an orphan, to not be related to a parent.
When you do the INSERT to the child table, you need to provide a non-NULL value for the foreign key column, if you want that row to reference a row in the parent table.
A foreign key can be defined with an ON DELETE SET NULL clause, but that would only be effective if you were to later delete a parent row that had children related to it. In that case, the child rows would have their foreign key column values set to NULL when the parent row is removed.
Mike said: I'm concerned that the child's foreign key is not getting populated by the parent.
The parent is not responsible for populating the foreign key column of the child. There's an option to have the child's foreign key value updated automatically when the parent's id value is changed... preserving the relationship: ON UPDATE CASCADE. But other than the actions performed by an ON UPDATE or ON DELETE clause, the parent has no responsibility of maintaining the values in a child table.
Mike asked: So how would I get the child's column to be populated from the parent?
You wouldn't. You would first locate (or insert) the row to the parent table. You would then preserve the value of the id column (or the values of whatever columns make up the PRIMARY KEY), and then use that same value for the foreign key column on the child row, when you insert a child row(s).
An error is returned when you set a foreign key to an arbitrary value (a value that does not match an existing PRIMARY KEY value in the parent table. That's the expected behavior.
If you are inserting the child row before the parent, you will need to leave the foreign key column as NULL, and then after you know the id value of the parent, you would then update the child row to set the foreign key column.
create table employee
( id int
, first varchar(128)
, last varchar(128)
, primary key(id) ) engine=innodb;
create table borrow
(ref auto_increment
, empID int
, book varchar(128)
, primary key(ref) ) engine=innodb;
alter table borrow add constraint fk_borrow
foreign key (empID) references employee(id);
insert into employee (id, first, last) values (1, 'foo', 'bar');
insert into borrow (empID, book) values (1,'mike');
insert into borrow (empID, book) values (1,'mulligan');
The two rows added to the borrow table are related to the row in employee, by virtue of the value in the foreign key column (empID) being set to a value that matches an id value in the employee table.

sql: change primary key to another list of unique elements

i want to change the ids of a table to some other unique value.
This is a simplified example:
CREATE TABLE IF NOT EXISTS test (
id int(11) NOT NULL,
reverse_id int(11) NOT NULL,
PRIMARY KEY (id),
UNIQUE KEY reverse_id (reverse_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO test (id, reverse_id) VALUES ('1', '2'), ('2', '1');
UPDATE test SET id = reverse_id;
# Duplicate entry '2' for key 'PRIMARY'
I am looking for a command that checks only at the end of the UPDATE for the uniqueness of the id elements.
[I know that I can create a second row and change the status of this row to primary, then i can update the ids and reset the primary status, but i want to have one command, without adding or changing other rows, tables]
This is not possible with MySQL as far as I know.
It neither evaluates constraint on statement level (it does that on row level while processing) nor does it allow you to define them to be deferred (so the constraint would be evaluated at commit time).
The only option I can see if you want to "renumber" your primary key: drop the primary key, renumber the ids then re-create the primary key.
What if you create the table having reverse_id as its primary key? - that is unique in your definition so it is a valid candidate for primary key.
Primary keys are unique by definition - this constraint is stopping you from achieving what you want