MySQL auto assign foreign key ID - mysql

I have a main table called results. E.g.
CREATE TABLE results (
r_id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
r_date DATE NOT NULL,
system_id INT NOT NULL,
FOREIGN KEY (system_id) REFERENCES systems(s_id) ON UPDATE CASCADE ON DELETE CASCADE
);
The systems table as:
CREATE TABLE systems (
s_id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
system_name VARCHAR(50) NOT NULL UNIQUE
);
I'm writing a program in Python with MySQL connector. Is there a way to add data to the systems table and then auto assign the generated s_id to the results table?
I know I could INSERT into systems, then do another call to that table to see what the ID is for the s_name, to add to the results table but I thought there might be quirk in SQL that I'm not aware of to make life easier with less calls to the DB?

You could do what you describe in a trigger like this:
CREATE TRIGGER t AFTER INSERT ON systems
FOR EACH ROW
INSERT INTO results SET r_date = NOW(), system_id = NEW.s_id;
This is possible only because the columns of your results table are easy to fill in from the data the trigger has access to. The auto-increment fills itself in, and no additional columns need to be filled in. If you had more columns in the results table, this would be harder.
You should read more about triggers:
https://dev.mysql.com/doc/refman/8.0/en/create-trigger.html
https://dev.mysql.com/doc/refman/8.0/en/triggers.html

Related

Why are there are two rows in MariaDB database violating unique constraint?

I have written an application in Javascript which inserts data into two tables via a connection to a MariaDB server.
There should be a 1:1 correspondance between the rows in these tables when first running the application.
One table stores (simulated) data about properties, the other table stores data about prices. There should be 1 price for each property. At a later date, the price might change, so there could be more than one entry for the price, but this cannot happen when the application is first run. These entries also cannot be in violation of a unique index - but they are.
Perhaps I have misconfigured something in MariaDB? Here is the code which generates the tables.
drop table if exists property_price;
drop table if exists property;
create table property
(
unique_id bigint unsigned not null auto_increment primary key,
web_id bigint unsigned not null,
url varchar(256),
street_address varchar(256),
address_country varchar(64),
property_type varchar(64),
num_bedrooms int,
num_bathrooms int,
created_datetime datetime not null,
modified_datetime datetime not null
);
create table property_price
(
property_unique_id bigint unsigned not null,
price_value decimal(19,2) not null,
price_currency varchar(64) not null,
price_qualifier varchar(64),
added_reduced_ind varchar(64),
added_reduced_date date,
created_datetime datetime not null
);
alter table property_price
add constraint fk_property_unique_id foreign key(property_unique_id)
references property(unique_id);
alter table property
add constraint ui_property_web_id
unique (web_id);
alter table property
add constraint ui_url
unique (url);
alter table property_price
add constraint ui_property_price
unique (property_unique_id, price_value, price_currency, price_qualifier, added_reduced_ind, added_reduced_date);
Below is a screenshot from DBeaver showing that a select statement returns two identical rows.
I don't understand why the unique constraint appears to be violated. The constraint does sometimes work, because if I run my application again, it fails because it attempts to insert a duplicate row which already exists in the DB. (Not the same as the one shown below.)
Can anyone point me in the right direction as to how I might debug this?
MariaDB permits multiple values on columns which form part of a unique constraint.
My solution would be to put the logic for checking for duplicate rows into the application, rather than this being on the database side. Essentially this means the unique constraint is not being used.

How to create sequence for a number that starts at 100 and increment by 5 in MySQL?

I need that the values for a ColumnID, which is a Primary Key, to start at 100 and increment by 5. This condition is asked to be included as a constraint before populating the tables. I already created the tables, I just need to add that constraint. I know I can't use AUTO_INCREMENT because the increase is only by 1. Is there a way to do it in MySQL?
MySQL does not provide any built-in function to create a sequence for a table's rows or columns. But we can generate it via SQL query.
Example:
Let us understand it with the help of the following example. First, we need to create a new table and make sure that there is one column with the AUTO_INCREMENT attribute and that too, as PRIMARY KEY.
Execute the below query to create a table:
CREATE TABLE Insects (
Id INT AUTO_INCREMENT PRIMARY KEY,
Name VARCHAR(30) NOT NULL,
Type VARCHAR(30) NOT NULL,
Origin VARCHAR(30) NOT NULL
);
Then you can alter your column to start from another value:
ALTER TABLE Insects AUTO_INCREMENT=100;
You can check it here.

MySQL autoincrement value range

Scenario is that I have 2 tables of the same structure, however I only want to allow php permissions to update table B, while table A can only be updated via DBMS.
These 2 tables are merged into a single php array, so I would like to set primary key ranges to seperate them at this point to avoid conflict of primary key (a simple autoincrement integer for best indexing).
As far as I know the simplest would be to constrain table A to have primary key auto increment values from 1000000 to 1999999 and then table B 2000000 upwards.
Is this possible to constrain min-max autoincrement values (I know I can start them at a given integer so asking if there is a simple 'max' to put on table A).
This simple configuration would ensure integrity.
Would an 'after_insert' type trigger work to remove the new row and throw an SQL error ?
You could create one table with id as mediumint (max 8 388 607 or twice as much for unsigned):
create table tableA( id mediumint(5) not null auto_increment, `test` varchar(5), primary key (id)) ;
and second with int and auto_increment value set over mediumint max:
create table tableB( id int(5) not null auto_increment, `test` varchar(5), primary key (id)) auto_increment=8388608 ;
https://dev.mysql.com/doc/refman/8.0/en/integer-types.html
But i think that much more elegant would be to utilize auto_increment_increment mechanism.
auto-increment-increment = 2 //global for all tables in mysql.ini
SET ##auto_increment_increment=2; //run-time just for one session
Set in tableA first auto_increment=1 and in tableB auto_increment=2 and You will never collide. One table will have odd ids and second will have even ids. This way You do not have to worry about reaching id limit.

mySql trigger not working as intended

I have 2 tables set up with a trigger, such that an insertion upon one table, will trigger an increment in the column of the second table at the same primary key (as both tables a linked by a foreign key), however at the moment the increment only once, then it does not increment for any subsequent insertions. My thinking is that it's probably with the way I set up the keys but I'm unsure, could someone please shed some light on this:
CREATE TABLE Members(
ID INT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE,
FIRST_NAME TEXT(16),
LAST_NAME TEXT(16),
TITLE TEXT(7), /** 7 CHARS for 'Student'*/
INSTITUTION VARCHAR(2048),
No_Publications INT NOT NULL,
PRIMARY KEY(ID)
);
CREATE TABLE Papers(
ISBN INT UNSIGNED NOT NULL UNIQUE,
Title TEXT(4),
Publish_Date DATE NOT NULL,
Topic TEXT(128),
PRIMARY KEY(ISBN)
);
CREATE TABLE Publications(
Author_ID INT UNSIGNED NOT NULL UNIQUE,
ISBN INT UNSIGNED NOT NULL UNIQUE,
PRIMARY KEY (Author_ID, ISBN),
FOREIGN KEY(Author_ID) REFERENCES Members(ID) ON DELETE RESTRICT ON UPDATE CASCADE,
FOREIGN KEY(ISBN) REFERENCES Papers(ISBN) ON DELETE RESTRICT ON UPDATE CASCADE /**Used in
many to many relations*/
);
CREATE TRIGGER New_Publication AFTER INSERT ON Publications
FOR EACH ROW
UPDATE Members SET No_Publications = No_Publications + 1
WHERE Members.ID = Publications.Author_ID;
EDIT: I want the No_Publications to increase with insertion upon the publications table
EDIT 2: After implementing the NEW keyword the auto-incrementation now works however now the following occurs:
Upon adding 1 new paper to 1 new member, the paper is registered in the database, however, subsequent additions of papers to the same member are not registered, despite and increment occuring in the members table.
Insertion into the Publications table occurs as a result of the papers table which has been appended above for transparency.
The trigger should be:
CREATE TRIGGER New_Publication AFTER INSERT ON Publications
FOR EACH ROW
UPDATE Members SET No_Publications = No_Publications + 1
WHERE Members.ID = NEW.Author_ID;
Even though his column should be updated also on deletes and having this column goes agains database normalization as you can get this information without having the column so it can be only useful in certain cases to improve performance and avoid counts.

Oracle DB - Primary Key Auto Increment Column without Sequence

I wonder if there is a way to create a table column with an primary key which is auto incremented without using a sequence.
I saw that it was working by using IDENTITY on Microsofts SQL Server and AUTO_INCREMENT on MySQL, but cannot get something that works with Oracle DB.
This is my current approach:
CREATE TABLE test
( id NUMBER(6) IDENTITY,
CONSTRAINT pk_id PRIMARY KEY (id)
)
Identity columns in Oracle would meet your requirement, but they were introduced in Oracle Database 12c.
Since you are on Oracle Database 11g, the best approach would be to use a sequence + trigger approach. Tim Hall has a good write up of this here:
Excerpt:
Create a table with a suitable primary key column and a sequence to
support it.
CREATE TABLE departments (
ID NUMBER(10) NOT NULL,
DESCRIPTION VARCHAR2(50) NOT NULL);
ALTER TABLE departments ADD (
CONSTRAINT dept_pk PRIMARY KEY (ID));
CREATE SEQUENCE dept_seq;
Create a trigger to populate the ID column if it's not specified in
the insert.
CREATE OR REPLACE TRIGGER dept_bir
BEFORE INSERT ON departments
FOR EACH ROW
WHEN (new.id IS NULL)
BEGIN
SELECT dept_seq.NEXTVAL
INTO :new.id
FROM dual;
END;