Is it possible to create a Unique (Index) constraint across multiple tables? - mysql

Is there a way to create a unique index across tables in a MySQL database?
By unique, I mean,
table A ids=1,2,5,7...
table B ids=3,4,6,8...

I think, it is not possible by directly creating a constraint. But there are some solutions in order for you to get unique IDs.
One suggestion would be is by using TRIGGER. Create a BEFORE INSERT trigger on both tables which checks the ID for existence during INSERT or UPDATE.
Second, is by creating a third table which contains UNIQUE numbers and the other tables: TableA and TableB will then be reference on the third one.

Like JW says, this would probably work well with using a third table. In MySQL, you can use identity fields to make this easier. A very simple example would be using these tables (simple versions of the tables with just names without knowing any further info):
CREATE TABLE a
(
`id` int,
`name` varchar(100),
PRIMARY KEY(`id`)
)
ENGINE = INNODB;
CREATE TABLE b
(
`id` int,
`name` varchar(100),
PRIMARY KEY(`id`)
)
ENGINE = INNODB;
CREATE TABLE c
(
`id` int auto_increment,
`intable` varchar(10) not null,
PRIMARY KEY(`id`)
)
ENGINE = INNODB;
Then, when you want to insert a value on either table, do (a sample inserting 'Joe' into a):
INSERT INTO c (`intable`) VALUES ('a');
INSERT INTO a (`id`, `name`)
SELECT LAST_INSERT_ID() AS id, 'Joe' AS name;
The only reason for the intable entry in c is so you know which table it was created for. Any sort of value to insert into c can be used instead.

Related

MySQL auto assign foreign key ID

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

How to use mysql join to deal with duplicate insertion when there is no primary key - MySQL

I have a table which looks like following
CREATE TABLE `groups` (
`id_rec` INT(11) NOT NULL DEFAULT '0',
`id_group` INT(11) NOT NULL DEFAULT '0',
UNIQUE INDEX `unikum` (`id_rec`, `id_group`),
INDEX `idxgroup` (`id_group`))
there is no primary key like id of the table on which i can use insert on duplicate key clause. Now i am trying to insert multiple rows with signle MySQL query in groups table, but i don't want insert duplicates. Now, the solution i came up with is creating and inserting in another temporary table and then use join on group table and temporary table in order to find duplicates or non-duplicates(new) records depending on the join that i should use.
The temporary table looks like following
CREATE TEMPORARY TABLE IF NOT EXISTS $tempTable
(id INT(11) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
group_id INT(11) NOT NULL,
id_rec INT(11) NOT NULL)
Now at this point i am not sure which join should i use. Any help would be grealty appreciated.
You don't need a primary key for ON DUPLICATE KEY UPDATE to work. The unique index you have is perfectly fine.
You can alternatively use INSERT IGNORE:
INSERT IGNORE INTO `groups` VALUES (1, 1);
If the pair (1, 1) already exists in your table then the above statement will be simply ignored.
Demo here

How to use fat-free ORM to insert data to id only table?

I have this table
CREATE TABLE IF NOT EXISTS `group` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`),
UNIQUE INDEX `id_UNIQUE` (`id` ASC))
ENGINE = InnoDB;
This is work.
INSERT INTO `group` (`id`) VALUES (NULL);
But I cannot insert record using fat-free
I tried this.
$group=new DB\SQL\Mapper($f3->get('DB'),'group');
$group->save();
and this.
$group=new DB\SQL\Mapper($f3->get('DB'),'group');
$group->id=null;
$group->save();
and this.
$group=new DB\SQL\Mapper($f3->get('DB'),'group');
$group->id='null';
$group->save();
But no one can create record, and also no error.
What is correct way to insert record to this table?
Fat-Free Framework's Mapper doesn't insert records without (changed/new) values besides the primary key. So the $fields array is empty and the Mapper skips the insert operation.
I am not sure if this qualifies as bug.
Here is a simple solution based on your provided query and F3's SQL object:
$sql = $f3->get('DB');
$sql->exec('INSERT INTO group (id) VALUES (NULL)');

Optimizing this MySQL Query

Table Schema
For the two tables, the CREATE queries are given below:
Table1: (file_path_key, dir_path_key)
create table Table1(
file_path_key varchar(500),
dir_path_key varchar(500),
primary key(file_path_key))
engine = innodb;
Table2: (file_path_key, hash_key)
create table Table2(
file_path_key varchar(500) not null,
hash_key bigint(20) not null,
foreign key (file_path_key) references Table1(file_path_key) on update cascade on delete cascade)
engine = innodb;
Objective:
Given a file_path F and it's dir_path string D, I need to find all those
file names which have at least one hash in the set of hashes of F, but
don't have their directory names as D. If a file F1 shares multiple hashes
with F, then it should be repeated that many times.
Note that the file_path_key column in Table1 and the hash_key column in Table2 are indexed.
In this particular case, Table1 has around 350,000 entries and Table2 has 31,167,119 entries, which makes my current query slow:
create table temp
as select hash_key from Table2
where file_path_key = F;
select s1.file_path_key
from Table1 as s1
join Table2 as s2
on s1.file_path_key join
temp on temp.hash_key = s2.hash_key
where s1.dir_path_key != D
How can I speed up this query?
I do not understand what is the purpose of temp table, but remember that such table, created with CREATE .. SELECT, does not have any indexes. So at the very least fix that statement to
CREATE TABLE temp (INDEX(hash_key)) ENGINE=InnoDB AS
SELECT hash_key FROM Table2 WHERE file_path_key = F;
Otherwise the other SELECT performs full join with temp, so it might be very slow.
I would also suggest using a numerical primary key (INT, BIGINT) in Table1 and reference it from Table2 rather than the text column. Eg:
create table Table1(
id int not null auto_increment primary key,
file_path_key varchar(500),
dir_path_key varchar(500),
unique key(file_path_key))
engine = innodb;
create table Table2(
file_id int not null,
hash_key bigint(20) not null,
foreign key (file_id) references Table1(id)
on update cascade on delete cascade) engine = innodb;
Queries joining the two tables may be a lot faster if integer columns are used in join predicate rather than text ones.

When to use different never-rejected ("insert or update") MySQL statements?

A standard problem in applications is to insert a record if one doesn't exist - or update if it does. In cases where the PRIMARY KEY is unknown this is usally solved by issuing a SELECT and then running either an INSERT or UPDATE if the record was found.
However, there seems to be at least three ways I know of that you can insert a record into a database even when a record already exists. Personally, I would rather drop the new insert request if one already exists, but then there might be cases where you would rather drop the record in the database and use the new one.
CREATE TABLE IF NOT EXISTS `table` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`foo` int(10) unsigned NOT NULL,
`bar` int(10) unsigned NOT NULL,
PRIMARY KEY (`id`),
KEY `row` (`foo`,`bar`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Here are the three methods:
INSERT IGNORE INTO table (foo, bar) VALUES (2,3);
INSERT INTO table (foo, bar) VALUES (2,3) ON DUPLICATE KEY UPDATE;
REPLACE INTO table (foo, bar) VALUES (2,3);
At what times should each of these methods be used?
Can someone give some examples of correct usage scenarios?
INSERT should be used when you just want to insert a new row
Lets say you are storing log entries, you'll want to log every event, use INSERT.
INSERT IGNORE should be used when you just want there to be a specific key exists in the table, it doesn't matter if it's the current insert that creates it, or if it's already present.
Let's say you have a table of phone-numbers and the number of uses, you find a new phone number that you are not sure exists in the table, but you want it to be there.
You use INSERT IGNORE to make sure that it's there.
REPLACE INTO should be used when you want to make sure that a specific key exists in the table, if it exists you'd like the new values to be used, instead of that present.
You have another table with phone-numbers, this time you find a new number and a name to associate it with.
You use REPLACE INTO to find and update a complete record, or just insert the new information.
INSERT INTO ... ON DUPLICATE KEY UPDATE ...
Please not that this is not an alternative method of writing REPLACE INTO, the above should be used whenever you'd like to make sure that a specific key exists, but if it does update some of the columns, not all of them.
For example if you are storing the numbers of visits from a certain IP, and the first page the user ever visited.
INSERT INTO visitors (ip,visits,first_page) VALUES (<ip>,1,<current_page>) ON DUPLICATE KEY visits = visits +1;
In your question, you have
INSERT INTO `table` (foo, bar) VALUES (2,3) ON DUPLICATE KEY UPDATE;
That can only work if the row index was UNIQUE:
CREATE TABLE IF NOT EXISTS `table` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`foo` int(10) unsigned NOT NULL,
`bar` int(10) unsigned NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `row` (`foo`,`bar`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Otherwise, why have just an index?
Also the ON DUPLICATE KEY clauses allows you to update non-indexed columns.
As for REPLACE, keep in mind that REPLACE is actually DELETE and INSERT under the hood.