29

Scenario:

I have a table which references two foreign keys, and for each unique combination of these foreign keys, has its own auto_increment column. I need to implement a Composite Key that will help identify the row as unique using combination of these three (one foreign keys and one auto_increment column, and one other column with non-unique values)

Table:

CREATE  TABLE `issue_log` (
`sr_no` INT NOT NULL AUTO_INCREMENT ,
  `app_id` INT NOT NULL ,
  `test_id` INT NOT NULL ,
  `issue_name` VARCHAR(255) NOT NULL ,
primary key (app_id, test_id,sr_no)
);

Of course, there has to be something wrong with my query, because of which the error thrown is:

ERROR 1075: Incorrect table definition; there can be only one auto column and it must be defined as a key

What I am trying to achieve:

I have an Application Table (with app_id as its primary key), each Application has a set of Issues to be resolved, and each Application has multiple number of tests (so the test_id col) The sr_no col should increment for unique app_id and test_id.

i.e. The data in table should look like:

enter image description here

The database engine is InnoDB. I want to achieve this with as much simplicity as possible (i.e. avoid triggers/procedures if possible - which was suggested for similar cases on other Questions).

Nirav Zaveri
  • 666
  • 1
  • 9
  • 27

6 Answers6

35

You can't have MySQL do this for you automatically for InnoDB tables - you would need to use a trigger or procedure, or user another DB engine such as MyISAM. Auto incrementing can only be done for a single primary key.

Something like the following should work

DELIMITER $$

CREATE TRIGGER xxx BEFORE INSERT ON issue_log
FOR EACH ROW BEGIN
    SET NEW.sr_no = (
       SELECT IFNULL(MAX(sr_no), 0) + 1
       FROM issue_log
       WHERE app_id  = NEW.app_id
         AND test_id = NEW.test_id
    );
END $$

DELIMITER ;
Robbie
  • 17,323
  • 4
  • 33
  • 71
noz
  • 1,823
  • 13
  • 13
  • Ok, and what changes should I do in my Create Table query? I can't make sr_no a Primary Key because its not gonna be unique. And I can't make it Autoincrement without making it Primary Key... – Nirav Zaveri Aug 08 '13 at 08:24
  • Just take the autoincrement off - it can't do what you want. The primary key stays the same. – noz Aug 08 '13 at 08:36
  • I am sorry I haven't worked with triggers, and this Trigger code is throwing out "Syntax Error" - with nothing else defined. Can you please clean up the code, and once done, put a comment here? The error is: ERROR 1064: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '.sr_no=(select ifnull(select max(sr_no)+1 from issue_log where app_id=new.app_id' at line 3 – Nirav Zaveri Aug 08 '13 at 08:38
  • Sorry there was a missing SET - I have added it into the text. – noz Aug 08 '13 at 10:16
  • Still and error; the error is on the line starting with "set..." and on second select, it shows "unexpected SELECT_SYM" syntax error. – Nirav Zaveri Aug 08 '13 at 11:07
  • Unbalanced brackets! Fixed in the answer. – noz Aug 08 '13 at 12:45
  • Thanks @noz. Will check it out! :) – Nirav Zaveri Aug 09 '13 at 04:40
  • I tried this solution and it didn't work for me. I wanted some auto_increment column based on another column. This would end up creating a deadlock. The solution I ended up going with looks like this. https://gist.github.com/russjohnson09/02323c148b60ed7805ce644340974a0c – russjohnson09 Feb 09 '17 at 19:47
7

You can do this with myISAM and BDB engines. InnoDB does not support this. Quote from MySQL 5.0 Reference Manual.

For MyISAM and BDB tables you can specify AUTO_INCREMENT on a secondary column in a multiple-column index. In this case, the generated value for the AUTO_INCREMENT column is calculated as MAX(auto_increment_column) + 1 WHERE prefix=given-prefix.

http://dev.mysql.com/doc/refman/5.0/en/example-auto-increment.html

Goran
  • 71
  • 1
  • 2
  • Just for your information, quoting the relevant information along with a link is always preferred on Stack Overflow, answers can be deleted for only referring the question asker to a link. – OGHaza Nov 27 '13 at 11:40
5

I don't fully understand your increment requirement on the test_id column, but if you want an ~autoincrement sequence that restarts on every unique combination of (app_id, test_id), you can do an INSERT ... SELECT FROM the same table, like so:

mysql> INSERT INTO `issue_log` (`sr_no`, `app_id`, `test_id`, `issue_name`) SELECT
           IFNULL(MAX(`sr_no`), 0) + 1 /* next sequence number */,
           3 /* desired app_id */,
           1 /* desired test_id */,
           'Name of new row'
           FROM `issue_log` /* specify the table name as well */
       WHERE `app_id` = 3 AND `test_id` = 1 /* same values as in inserted columns */

This assumes a table definition with no declared AUTO_INCREMENT column. You're essentially emulating autoincrement behavior with the IFNULL(MAX()) + 1 clause, but the manual emulation works on arbitrary columns, unlike the built-in autoincrement.

Note that the INSERT ... SELECT being a single query ensures atomicity of the operation. InnoDB will gap-lock the appropriate index, and many concurrent processes can execute this kind of query while still producing non-conflicting sequences.

Rolf NB
  • 103
  • 1
  • 5
  • The project is over. But hopefully this will help someone who stumble across. I am not sure of my question back then :P – Nirav Zaveri Feb 19 '15 at 06:58
  • 2
    Insert-select isn't necessarily atomic. It depends on your locking settings/isolation level. See http://stackoverflow.com/questions/21438033/making-an-insert-select-statement-atomic, or http://dba.stackexchange.com/questions/73540/mysql-consistent-nonlocking-reads-vs-insert-select. – HardlyKnowEm Mar 06 '15 at 22:22
3

You can use a unique composite key for sr_no,app_id & test_id. You cannot use incremental in sr_no as this is not unique.

CREATE TABLE IF NOT EXISTS `issue_log` (
  `sr_no` int(11) NOT NULL,
  `app_id` int(11) NOT NULL,
  `test_id` int(11) NOT NULL,
  `issue_name` varchar(255) NOT NULL,
  UNIQUE KEY `app_id` (`app_id`,`test_id`,`sr_no`)
) ENGINE=InnoDB ;

I have commented out unique constraint violation in sql fiddle to demonstrate (remove # in line 22 of schema and rebuild schema )

david strachan
  • 7,141
  • 2
  • 22
  • 33
0

Just add key(sr_no) on auto-increment column:

CREATE  TABLE `issue_log` (
 `sr_no` INT NOT NULL AUTO_INCREMENT ,
 `app_id` INT NOT NULL ,
 `test_id` INT NOT NULL ,
 `issue_name` VARCHAR(255) NOT NULL ,
  primary key (app_id, test_id,sr_no),
  key (`sr_no`)
);
Pavel Katiushyn
  • 795
  • 4
  • 9
0

Why don't you try to change the position of declare fields as primary key, since when you use "auto_increment" it has to be referenced as the first. Like in the following example

CREATE  TABLE `issue_log` (
`sr_no` INT NOT NULL AUTO_INCREMENT ,
  `app_id` INT NOT NULL ,
  `test_id` INT NOT NULL ,
  `issue_name` VARCHAR(255) NOT NULL ,
primary key (sr_no,app_id, test_id)
);