Retrieving last inserted ID for InnoDB composite key table - php

I have the following table:
CREATE TABLE `my_table` (
composite_pk1 INT NOT NULL ,
composite_pk2 INT NOT NULL ,
data VARCHAR(255) NOT NULL ,
primary key (composite_pk1, composite_pk2)
) ENGINE=InnoDB;
For a given composite_pk1, I wish composite_pk2 to act as an autoincrement primary key. I don't wish to lock the table, and as such plan on using a trigger such as the following:
DELIMITER $$
CREATE TRIGGER my_trigger BEFORE INSERT ON my_table
FOR EACH ROW BEGIN
SET NEW.composite_pk2 = (
SELECT IFNULL(MAX(composite_pk2), 0) + 1
FROM issue_log
WHERE composite_pk1 = NEW.composite_pk1
);
END $$
I can now insert a record:
$stmt=$myDB->prepare('INSERT INTO my_table(composite_pk1, data) VALUES (?,?)');
$stmt->execute([123,'hello']);
How do I get the last inserted composite_pk2? PDO::lastInsertId only works with native autoincrement tables (i.e. not the trigger approach). I "could" later do a SELECT query to get the max value, however, there is no guarantee that another record has snuck in.

You can make composite_pk2 an unique key with auto_increment:
CREATE TABLE `my_table` (
composite_pk1 INT NOT NULL ,
composite_pk2 INT NOT NULL unique auto_increment,
data VARCHAR(255) NOT NULL ,
primary key (composite_pk1, composite_pk2)
) ENGINE=InnoDB;
Now last_insert_id() will return the recently created id for composite_pk2.

Related

SQL: Getting values which all other values related to each must be in another table

I'm working in a web page with PHP and MySQL where I have this DB:
CREATE TABLE action (
idaction INT NOT NULL AUTO_INCREMENT,
--Other columns
PRIMARY KEY (`idaction`));
CREATE event (
idevent INT NOT NULL AUTO_INCREMENT,
--Other columns
PRIMARY KEY (`idevent`));
CREATE TABLE currentGame (
user_email VARCHAR(45) NOT NULL,
--Other columns
PRIMARY KEY (`user_email`));
CREATE TABLE IF NOT EXISTS currentEvents (
currentGame_user_email VARCHAR(45) NOT NULL,
event_idevent INT NOT NULL,
PRIMARY KEY (currentGame_user_email, event_idevent),
FOREIGN KEY (currentGame_user_email) REFERENCES currentGame (user_email),
FOREIGN KEY (event_idevent) REFERENCES event (idevent));
CREATE TABLE IF NOT EXISTS spawnConditions (
action_idaction INT NOT NULL,
event_idevent INT NOT NULL,
PRIMARY KEY (action_idaction, event_idevent),
FOREIGN KEY (action_idaction) REFERENCES action (idaction),
FOREIGN KEY (event_idevent) REFERENCES event (idevent));
So I need to do a query which has the actions which fulfill any of these conditions:
It is not in spawnConditions.
If it is in spawnConditions, all the events which it is related to in this table, must be in the subgroup of currentEvent with a certain known user_email.
In other words, for action A1, being in spawnConditions with events E1 and E2, to be able to be selected from table action, both E1 and E2 must be in currentEvents with the known currentGame_user_email.
Can it be written using only SQL or do I need to involve PHP?
I think that not exists can get the work done here. Basically, you want to filter out actions for which a corresponding record exists in currentEvents with a currentGame_user_email other than a fixed value:
select a.*
from action a
where not exists (
select 1
from spawnConditions sc
inner join currentEvents ce
on ce.event_idevent = sc.event_idevent
where
sc.action_idaction = a.idaction
and ce.currentGame_user_email <> ?
)
The question mark represents the "certain known user_email" you mentioned in the question.

Combination of two columns as unique Key in mysql

Need to set a unique key by combining two column in mysql. For example
id Ticket_number Code Name
1 5 123 a
2 5 89 b
3 2 89 a
4 8 123 c
Here I want to set the Ticket_number and Code as unique by combining both. i.e error should be occur only if the same combination occurs again. Ticket Number and code can be duplicated but the combination should not be duplicated. How is it possible. Please help me.
Here is the create statement:
CREATE TABLE arlog (
id int(11) NOT NULL AUTO_INCREMENT,
Ticket_Number varchar(40) NOT NULL,
Code varchar(10) NOT NULL,
Name varchar(100) NOT NULL,
PRIMARY KEY (id),
UNIQUE KEY Ticket_Number (Ticket_Number)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1;
Create a unique index:
create unique index idx_table_ticket_code on table(ticket_number, code)
use this code to create table
CREATE TABLE ticket(
id INT,
ticket_number INT,
code INT,
PRIMARY KEY (id)
)
CREATE UNIQUE INDEX index_name ON ticket(id, ticket_number, code);
which will act as a composite key.
follow as given
CREATE TABLE tablename (
id INT,
user_id INT,
setting_id INT,
NAME VARCHAR(255)
);
CREATE UNIQUE INDEX index_name ON tablename(user_id, setting_id);
INSERT INTO tablename (NAME,user_id,setting_id) VALUES ('1',34,15)
ON DUPLICATE KEY UPDATE NAME = '1', user_id = 34, setting_id = 15;
traffic_hit_reports is a table name, ALTER TABLE change the table schema, ADD UNIQUE add the unique constraint and content_id,hit_date is a field name.
Now,
ALTER TABLE `traffic_hit_reports` ADD UNIQUE `unique_index`(`content_id`,`hit_date`);
Result:

mysql 'likes' structure table

I'm working on a web site where users can post articles with this table structure :
CREATE TABLE IF NOT EXISTS `articles` (
`id_articles` int(10) unsigned NOT NULL AUTO_INCREMENT,
`id_users` int(10) unsigned NOT NULL,
`articles` text NOT NULL,
PRIMARY KEY (`id_articles`),
UNIQUE KEY `id_articles` (`id_articles`),
KEY `id_users` (`id_users`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
Each user can 'like' the articles.
Is that the right way below to create a 'like table' :
CREATE TABLE IF NOT EXISTS `articles_likes` (
`id_articles` int(10) unsigned NOT NULL,
`id_users` int(10) unsigned NOT NULL,
KEY `id_articles` (`id_articles`,`id_users`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
It is correct but you will want to add separte indexes on id_articles and id_users (also you might want to name the columns 'id_article' and 'id_user' for sanity).
CREATE TABLE IF NOT EXISTS `article_likes` (
`id_article` int(10) unsigned NOT NULL,
`id_user` int(10) unsigned NOT NULL,
KEY `id_article` (`id_article`),
KEY `id_user` (`id_user`)
) ENGINE=InnoDB;
The reason you want separate indexes is because in mysql if you create an index on columns (A, B) that index will be used in queries having in the where clause column A, or columns A and B.
In your case for example if you made a query "SELECT * FROM article_likes WHERE id_user=X" this query would not use an index.
An ever better option would be to add a combined index and a separate index on the second column from the combined index. Like this:
CREATE TABLE IF NOT EXISTS `article_likes` (
`id_article` int(10) unsigned NOT NULL,
`id_user` int(10) unsigned NOT NULL,
KEY `id_article_user` (`id_article`, `id_user`),
KEY `id_user` (`id_user`)
) ENGINE=InnoDB;
This way you would have optimal performance on queries like 'WHERE id_user=X', "WHERE id_article=X', "WHERE id_article=X AND id_user=Y"
This is a valid way Chris. You can use COUNT() to match the id_articles in the articles_likes table against the current article you are viewing in articles.
$articles_id = 23;
mysql_query("SELECT COUNT(*) FROM articles_likes
WHERE id_articles = ".$articles_id);
You can also just leave COUNT() (MySQL) out and instantly know which users are the "likers" of the articles and use count() (PHP) on the returned Array to duplicate the effect of COUNT() in MySQL.
i would have a total of 3 tables. an articles table, and the user id could be a column in that for users who submit articles , but you need a separate user table since not all users will submit articles (i am assuming), and then a 3rd table for likes, that takes the primary key from users and the primary key from articles and uses them as foreign keys. so each time an article is liked, an entry is made in the 3rd table

what's wrong with this SQL statement causing column count doesn't match value count at row 1?

Mysql table (migration_terms) fields are as follows
oldterm count newterm seed
I used the following create table statment.
CREATE TABLE `migration_terms`
(
`oldterm` varchar(255) DEFAULT NULL,
`count` smallint(6) DEFAULT '0',
`newterm` varchar(255) DEFAULT NULL,
`seed` int(11) NOT NULL AUTO_INCREMENT, PRIMARY KEY (`seed`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
And It works, no problems there.
but then when I used the following insert into statement to populate it;
"INSERT INTO migration_terms
SELECT looseterm as oldterm,
COUNT(seed) AS count
FROM looseterms
GROUP BY looseterm
ORDER BY count DESC "
I get this error;
Column count doesn't match value count at row 1
I cannot figure out why?
If you need the table structure of the looseterms table, it was created by the following create table statement.
CREATE TABLE looseterms
(
`seed` INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
`looseterm` varchar(255)
)
You need to specify the columns if your select statement has fewer columns than the table
"INSERT INTO migration_terms
(oldterm,
count)
SELECT looseterm AS oldterm,
Count(seed) AS count
FROM looseterms
GROUP BY looseterm
ORDER BY count DESC "
From MySql docs on Insert Syntax
If you do not specify a list of column names for INSERT ... VALUES or
INSERT ... SELECT, values for every column in the table must be
provided by the VALUES list or the SELECT statement. If you do not
know the order of the columns in the table, use DESCRIBE tbl_name to
find out.
Your insert is adding 2 columns of data, whereas your table's definition has 4 columns

how to implement constraint in table such that inserted values do not repeat for group of rows only

I have to construct a table with columns
col1(primary key) col2(not null) col3(not null) col4(not null)
Now I need to insert values into this table such that values inserted into col3 don't repeat for set of values in col2....what are the constraints that is need to implement??...
Values can repeat in col3 as a whole ...But for some set of values of col2 values in col3 need not repeat.
So this is the column name.
ID ID_Category Keywords Score
Values in Keywords column can repeat - but for some values in ID_Category, Keywords values need not repeat.
Can you help me how to implement this??
Using code from http://forge.mysql.com/wiki/Triggers#Emulating_Check_Constraints
First create this general purpose error table
CREATE TABLE `Error` (
`ErrorGID` int(10) unsigned NOT NULL auto_increment,
`Message` varchar(128) default NULL,
`Created` timestamp NOT NULL default CURRENT_TIMESTAMP
on update CURRENT_TIMESTAMP,
PRIMARY KEY (`ErrorGID`),
UNIQUE KEY `MessageIndex` (`Message`))
ENGINE=MEMORY
DEFAULT CHARSET=latin1
ROW_FORMAT=FIXED
COMMENT='The Fail() procedure writes to this table twice to force a constraint failure.';
A generic function created to fail
DELIMITER $$
DROP PROCEDURE IF EXISTS `Fail`$$
CREATE PROCEDURE `Fail`(_Message VARCHAR(128))
BEGIN
INSERT INTO Error (Message) VALUES (_Message);
INSERT INTO Error (Message) VALUES (_Message);
END$$
DELIMITER ;
Now you are armed to create custom constraints on any table, such as yours
DELIMITER $$
create trigger mytable_check before insert on test.mytable for each row
begin
if new.id_category in ('list','of','special','categories')
and exists
(select * from mytable
where id_category=new.id_category
and keywords=new.keywords) then
call fail(concat('id_category,keywords must be unique when id_category is: ',new.id_category));
end if;
end $$
DELIMITER ;

Categories