Adding auto increment column other than primary key - mysql

I have table in which has key is primary key. I want to add seqNo key which should be auto incremented but it does not allow to make it as auto increment.
Because there is already one primary key,
Is it possible to make seqNo auto increment? currently seqNo is not present. I want to add it

You can't have two identity columns in a SQL table but you can still create sequences. Here's the link http://technet.microsoft.com/en-us/library/ff878091.aspx

You have the following options.
Make a trigger that increments your column value on every insert statement
Use a sequence, but once a sequence value is generated it will never be generated again (meaning, you would get a gap in your values if your insert fails for some reason)

Vignesh, consider the following...
DROP TABLE IF EXISTS test;
CREATE TABLE test
( testID int(11) NOT NULL
, string varchar(45) DEFAULT NULL
, testInc int(11) NOT NULL AUTO_INCREMENT
, PRIMARY KEY (testID)
, KEY testInc (testInc)
);
INSERT INTO test
(testID
, string
) values
(1
,'Hello'
);
INSERT INTO test (testid,string) SELECT x.testid + y.max_test,string FROM test x JOIN (SELECT MAX(testid) max_test FROM test)y;
INSERT INTO test (testid,string) SELECT x.testid + y.max_test,string FROM test x JOIN (SELECT MAX(testid) max_test FROM test)y;
INSERT INTO test (testid,string) SELECT x.testid + y.max_test,string FROM test x JOIN (SELECT MAX(testid) max_test FROM test)y;
Query OK, 4 rows affected (0.03 sec)
SELECT * FROM test;
+--------+--------+---------+
| testID | string | testInc |
+--------+--------+---------+
| 1 | Hello | 1 |
| 2 | Hello | 2 |
| 3 | Hello | 3 |
| 4 | Hello | 4 |
| 5 | Hello | 6 |
| 6 | Hello | 7 |
| 7 | Hello | 8 |
| 8 | Hello | 9 |
+--------+--------+---------+
Note that the number of rows (8), and the value of testinc (9) are different. This is not what the OP wants. The MAX() trick I've used for generating the PK is also no good, because it's subject to runtime errors.
fiddle of same http://www.sqlfiddle.com/#!2/d29a5b/1
The point is... storing a sequential id is pointless.

Related

Create a view and don't let the database update mysql?

create table Branch
(
BranchNo char(4),
Street varchar(30),
City varchar(30),
PostCode varchar(10)
)
INSERT INTO BRANCH
VALUES ('B002', '55 cOVER', 'LONDON',NULL)
INSERT INTO BRANCH
VALUES ('B003', '163 Main Street', 'Glasgow',NULL)
INSERT INTO BRANCH
VALUES ('B004', '32 Manse Road', 'Bristol',NULL)
INSERT INTO BRANCH
VALUES ('B005', '22 Dear Road', 'LONDON',NULL)
INSERT INTO BRANCH
VALUES ('B007', '16 Argyll', 'Abend',NULL)
Create a view named ViewDeC that displays information of all branches. Must say
make sure it is not possible to update the data for the branch table (Branch) through this View
Create a view and don't let the database update mysql?
enter image description here
If I am not mistaken, this is about how to create a readonly view. Though MySQL does not support creating a view with readonly attribute DIRECTLY, certain things can be done to make the view READONLY. One workaround is to make the view through joined tables.
create view ViewDeC as
select BranchNo,Street,City,PostCode
from Branch
join (select 1) t;
select * from ViewDec;
INSERT INTO ViewDec
VALUES ('B009', '99 Argyll', 'bender',NULL);
-- Error Code: 1471. The target table ViewDec of the INSERT is not insertable-into
Note, this is implemented at the cost of some performance, but not terribly unbearable. I have a table with 1.4 million rows. Here is the test with and without join using a table scan as the access method.
select * from proctable;
-- 1429158 rows in set (1.26 sec)
select * from proctable join (select 1) t;
-- 1429158 rows in set (1.40 sec)
However, for an index lookup access method, this is almost non-existent.
select * from proctable join (select 1) t where id between 100 and 500;
-- 401 rows in set (0.00 sec)
explain select * from proctable join (select 1) t where id between 100 and 500;
+----+-------------+------------+------------+--------+---------------+---------+---------+------+------+----------+----------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+------------+------------+--------+---------------+---------+---------+------+------+----------+----------------+
| 1 | PRIMARY | <derived2> | NULL | system | NULL | NULL | NULL | NULL | 1 | 100.00 | NULL |
| 1 | PRIMARY | proctable | NULL | range | PRIMARY | PRIMARY | 4 | NULL | 401 | 100.00 | Using where |
| 2 | DERIVED | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | No tables used |
+----+-------------+------------+------------+--------+---------------+---------+---------+------+------+----------+----------------+

How to make SQL Primary key have a specific number of characters?

I'm working on a MySQL database for shop items. I want these shop items to have IDs like 0001, 0002 etc. But if I use AUTO_INCREMENT (which I need) it will go as 1, 2 etc. Is there any way to make AUTO_INCREMENT for PRIMARY KEY work this way because I need IDs to have a specific number of characters?
This is the code where I'm creating the items table:
CREATE TABLE items (
item_id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(30) NOT NULL,
price FLOAT NOT NULL,
discount INT
);
This is the Python loop where I'm putting all items from .csv file into the database table:
for item in items_list:
mycursor.execute(f"INSERT INTO items(name, price, discount) VALUES ({item['name']}, {item['price']}, {item['discount']});")
Is it possible to make AUTO_INCREMENT work that way or I need to do it manually?
Primary keys need to have one job only, that of uniquely identifying a row. As soon as you start trying to make them look presentable by formatting them or make them sequential without gaps, or even when you try to use them to see if one row was created before another, you create reasons to want to change them.
Practically anything visible to users or involved in business logic is going to end up needing to change. And primary keys shouldn't change. Changing a primary key means deleting the row and making a new one with the new key value, and also fixing all the references to the old key. It's fiddly and tedious and error-prone, it is something you want to avoid.
Make a separate column for a user-visible identifier separate from the PK that you can have full control over. You can populate it with a trigger or application code based off the key if you want. Just keep it separate from the primary key.
Auto_incrememts are tricky, because they can't be used in BEFORE INSERT TRIGGER it is alays 0
so you need another table and a AFTER INSERT TRIIGGER
CREATE TABLE items (
item_id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(30) NOT NULL,
price DECIMAL(10,2) NOT NULL,
discount INT
);
CREATE TABLE t1 (
item_id_1 varchar(8) )
CREATE TRIGGER ins_sum AFTER INSERT ON items
FOR EACH ROW INSERT INTO t1 VALUES(LPAD (NEW.item_id , 8, '0'));
INSERT INTO items (name,price, discount) VALUES ('test1',1.1,1)
INSERT INTO items (name,price, discount) VALUES ('test2',1.1,1)
INSERT INTO items (name,price, disc
SELECT * FROM t1
| item_id_1 |
| :-------- |
| 00000001 |
| 00000002 |
| 00000003 |
SELECT *,(SELECT item_id_1 FROM t1 WHERE item_id_1 + 0 = i.item_id) FROM items i
item_id | name | price | discount | (SELECT item_id_1 FROM t1 WHERE item_id_1 + 0 = i.item_id)
------: | :---- | ----: | -------: | :---------------------------------------------------------
1 | test1 | 1.10 | 1 | 00000001
2 | test2 | 1.10 | 1 | 00000002
3 | test3 | 1.10 | 1 | 00000003
SELECT i.*,t1.item_id_1 FROM items i JOIN t1 ON i.item_id = t1.item_id_1 + 0
item_id | name | price | discount | item_id_1
------: | :---- | ----: | -------: | :--------
1 | test1 | 1.10 | 1 | 00000001
2 | test2 | 1.10 | 1 | 00000002
3 | test3 | 1.10 | 1 | 00000003
db<>fiddle here

SQL: What would happen if, hypothetically, an out of place number was added to the unique identifier column?

Lets think of it this way, say I have a table called "names" in MYSQL like so:
id| name
1 | Bob
2 | Sally
3 | Anne
Where "id" is a unique identifier for the table, and auto-increments with every addition of a row.
Say I somehow managed to throw in a row with an id that is completely out of place in the order, like so:
id| name
1 | Bob
2 | Sally
3 | Anne
20| John
Would the rows following the random row continue from the new id 20? (e.g next row added has id 21), or would they still continue from id 3? (e.g next row added has id 4)
Has this happened in SQl before?
They will continue with 21, which prohibits duplicates. Otherwise you would have a problem when you reach 19 and the next inserted row should become 20, which is already there.
By the way it is not complicated to insert such a row. Just provide a specific value on INSERT instead of leaving out the auto-increment column or handing over NULL.
Unless you set the next-autoincrement value manually, MySQL does everything to assure that one does not run into conflicts. So if you insert a big value, it saves this+1 as next autoincrement value.
To see what the next auto increment for mysql table will be, use
SHOW TABLE STATUS LIKE 'tablename';
There you will have Auto_increment column which says what is the next auto increment value. For the sake of test and curiosity I have conducted the following test:
I have created the table as follows:
CREATE TABLE `test` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`num` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1
Then I have conducted following queries:
INSERT INTO `test` (`id`,`num`) VALUES (NULL,1);
INSERT INTO `test` (`id`,`num`) VALUES (NULL,2);
INSERT INTO `test` (`id`,`num`) VALUES (NULL,3);
INSERT INTO `test` (`id`,`num`) VALUES (50,4);
INSERT INTO `test` (`id`,`num`) VALUES (NULL,5);
Output is as follows:
mysql> select * from `test`;
+----+------+
| id | num |
+----+------+
| 1 | 1 |
| 2 | 2 |
| 3 | 3 |
| 50 | 4 |
| 51 | 5 |
+----+------+
5 rows in set (0.00 sec)
Which means, that after you insert your custom value, Auto_increment also gets incremented. Then I have executed one more query:
INSERT INTO `test` (`id`,`num`) VALUES (100,6);
And after that status is as follows
mysql> SHOW TABLE STATUS LIKE 'test';
+------+--------+---------+------------+------+----------------+-------------+-----------------+--------------+-----------+----------------+---------------------+-------------+------------+-------------------+----------+----------------+---------+
| Name | Engine | Version | Row_format | Rows | Avg_row_length | Data_length | Max_data_length | Index_length | Data_free | Auto_increment | Create_time | Update_time | Check_time | Collation | Checksum | Create_options | Comment |
+------+--------+---------+------------+------+----------------+-------------+-----------------+--------------+-----------+----------------+---------------------+-------------+------------+-------------------+----------+----------------+---------+
| test | InnoDB | 10 | Compact | 6 | 2730 | 16384 | 0 | 0 | 8388608 | 101 | 2014-02-26 22:12:32 | NULL | NULL | latin1_swedish_ci | NULL | | |
+------+--------+---------+------------+------+----------------+-------------+-----------------+--------------+-----------+----------------+---------------------+-------------+------------+-------------------+----------+----------------+---------+
1 row in set (0.00 sec)
You can see that next auto increment value is going to be 101, which means that MySQL automatically adjusts to the inserted values.
Let me know what you think.

MySQL INSERT .. UPDATE breaks AUTO_INCREMENT?

There are the following two tables:
create table lol(id int auto_increment, data int, primary key id(id));
create table lol2(id int auto_increment, data int, primary key id(id));
Insert some values:
insert into lol2 (data) values (1),(2),(3),(4);
Now insert using select:
insert into lol (data) select data from lol2;
Do it again:
insert into lol (data) select data from lol2;
Now look at the table:
select * from lol;
I receive:
+----+------+
| id | data |
+----+------+
| 1 | 1 |
| 2 | 2 |
| 3 | 3 |
| 4 | 4 |
| 8 | 1 |
| 9 | 2 |
| 10 | 3 |
| 11 | 4 |
+----+------+
I'm puzzled by the gap between 4 and 8... What caused this and how can I do it so that there isn't a gap? Thanks a lot!
auto_increment does not guarantee to have increments by 1 in the ID column. And it cannot, because as soon as you work with parallel transactions it would break anyways:
BEGIN BEGIN
INSERT INTO lol VALUES(...) INSERT INTO lol VALUES(..)
... ...
COMMIT ROLLBACK
What ids should be assigned by the database? It cannot know in advance which transaction will succeed and which will be rolled back.
If you need a sequential numbering of your records you would use a query which returns that; e.g.
SELECT COUNT(*) as position, lol.data FROM lol
INNER JOIN lol2 ON lol.id < lol2.id
GROUP BY lol.id

MySQL Alter table, add column with unique random value

I have a table that I added a column called phone - the table also has an id set as a primary key that auto_increments. How can I insert a random value into the phone column, that won't be duplicated. The following UPDATE statement did insert random values, but not all of them unique. Also, I'm not sold I cast the phone field correctly either, but ran into issues when trying to set it as a int(11) w/ the ALTER TABLE command (mainly, it ran correctly, but when adding a row with a new phone number, the inserted value was translated into a different number).
UPDATE Ballot SET phone = FLOOR(50000000 * RAND()) + 1;
Table spec's
+------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| phone | varchar(11) | NO | | NULL | |
| age | tinyint(3) | NO | | NULL | |
| test | tinyint(4) | NO | | 0 | |
| note | varchar(100) | YES | | NULL | |
+------------+--------------+------+-----+---------+----------------+
-- tbl_name: Table
-- column_name: Column
-- chars_str: String containing acceptable characters
-- n: Length of the random string
-- dummy_tbl: Not a parameter, leave as is!
UPDATE tbl_name SET column_name = (
SELECT GROUP_CONCAT(SUBSTRING(chars_str , 1+ FLOOR(RAND()*LENGTH(chars_str)) ,1) SEPARATOR '')
FROM (SELECT 1 /* UNION SELECT 2 ... UNION SELECT n */) AS dummy_tbl
);
-- Example
UPDATE tickets SET code = (
SELECT GROUP_CONCAT(SUBSTRING('123abcABC-_$#' , 1+ FLOOR(RAND()*LENGTH('123abcABC-_$#')) ,1) SEPARATOR '')
FROM (SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5) AS dummy_tbl
);
Try this
UPDATE Ballot SET phone = FLOOR(50000000 * RAND()) * id;
I'd tackle this by generating a (temporary) table containing the numbers in the range you need, then looping through each record in the table you wish to supply with random numbers. Pick a random element from the temp table, update the table with that, and remove it from the temp table. Not beautiful, nor fast.. but easy to develop and easy to test.