It's easy to create a database table for storing sequence numbers ; but this design is suited for the event when the sequence is shared for all users. What I want is to create sequence for each group of users : this group can grow at any time because it's a database table , that is the administrator can create a group at any time and users are assigned to a specific group. So how to implement the sequence generation according to a group ?
if you are using myisam
http://dev.mysql.com/doc/refman/5.0/en/example-auto-increment.html
Below extracted from above links.
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. This is
useful when you want to put data into ordered groups.
CREATE TABLE animals (
grp ENUM('fish','mammal','bird') NOT NULL,
id MEDIUMINT NOT NULL AUTO_INCREMENT,
name CHAR(30) NOT NULL,
PRIMARY KEY (grp,id)
) ENGINE=MyISAM;
INSERT INTO animals (grp,name) VALUES
('mammal','dog'),('mammal','cat'),
('bird','penguin'),('fish','lax'),('mammal','whale'),
('bird','ostrich');
SELECT * FROM animals ORDER BY grp,id;
Which returns:
+--------+----+---------+
| grp | id | name |
+--------+----+---------+
| fish | 1 | lax |
| mammal | 1 | dog |
| mammal | 2 | cat |
| mammal | 3 | whale |
| bird | 1 | penguin |
| bird | 2 | ostrich |
+--------+----+---------+
For your case:
CREATE TABLE mytable (
user_id MEDIUMINT NOT NULL AUTO_INCREMENT,
group_id MEDIUMINT NOT NULL,
user_name CHAR(30) NOT NULL,
PRIMARY KEY (group_id,user_id)
) ENGINE=MyISAM;
INSERT INTO mytable (group_id, user_name) VALUES
(1,'alex'),(1,'jenny'),(2,'baz'),(1,'tim'),(2,'danny'),(3,'joe');
SELECT * FROM mytable ORDER BY group_id,user_id;
Returns:
user_id group_id user_name
1 1 alex
2 1 jenny
3 1 tim
1 2 baz
2 2 danny
1 3 joe
Related
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
I have a unique situation where I need to pull many records, but sort SOME at the top if they are considered "favorites"...but then I need to pull all the rest of the records below this group.
Can this be done in one query...or will I need two? Any examples?
You can have a custom Order By with a CASE/WHEN clause:
Schema:
create table music
( mId int auto_increment primary key,
song varchar(100) not null
);
create table person
( pId int auto_increment primary key,
pName varchar(100) not null
);
create table person_owns_music
( id int auto_increment primary key,
mId int not null,
pId int not null,
favorite int not null,
rating int not null, -- 100 loves it. 0 hates it
foreign key `pom_2_music` (mId) references music(mId),
foreign key `pom_2_person` (pId) references person(pId)
);
-- truncate table person_owns_music;
insert music(song) values ('s1'),('s2'),('s3'),('s4'),('s5'),('s6');
insert person(pName) values ('p1'),('p2'),('p3');
insert person_owns_music(mId,pId,favorite,rating) values
(1,1,1,10),(2,1,1,100),(3,1,0,65),(4,1,1,15),(6,1,1,5),
(1,2,1,10),(2,2,1,100),(5,2,1,100);
Query:
SELECT pom.mId,m.song,pom.favorite,pom.rating
FROM person_owns_music pom
JOIN music m ON m.mId=pom.mId
WHERE pom.pId=1
ORDER BY CASE pom.favorite
WHEN 1 THEN 1
WHEN 0 THEN 2
END, pom.rating DESC;
+-----+------+----------+--------+
| mId | song | favorite | rating |
+-----+------+----------+--------+
| 2 | s2 | 1 | 100 |
| 4 | s4 | 1 | 15 |
| 1 | s1 | 1 | 10 |
| 6 | s6 | 1 | 5 |
| 3 | s3 | 0 | 65 |
+-----+------+----------+--------+
I have the following tables:
machine_machine
id | machineid
1 | EE100034442
item_item
id | upc | name
2 | 10001 | Snickers
machine_setup
id | machine_id | selection | item_id
3 | 1 | A1 | 1
Im trying to get the following output by joining the tables.
machine_setup.machine_id=machine_machine.machineid, machine_setup.selection, item_item.upc, item_item.name
EE100034442 A1 10001 Snickers
Table machine_setup will by the main referenced table as it has multiple selection for each machine_id.
Based on the only id's I can see at the moment to join on, consider this:
create table machine_machine
( id int auto_increment primary key,
machineid varchar(50) not null
);
create table item_item
( id int auto_increment primary key,
upc varchar(30) not null,
name varchar(100) not null
);
create table machine_setup
( id int auto_increment primary key,
machine_id int not null,
selection varchar(30) not null
);
insert machine_machine(machineid) values ('EE100034442');
insert item_item(upc,name) values ('10001','Snickers');
insert machine_setup(machine_id,selection) values (1,'A1'),(1,'A2'),(1,'A(n)');
select mm.machineid,ms.selection,ii.upc,ii.name
from machine_setup ms
join machine_machine mm
on mm.id=ms.machine_id
join item_item ii
on ii.id=ms.machine_id;
+-------------+-----------+-------+----------+
| machineid | selection | upc | name |
+-------------+-----------+-------+----------+
| EE100034442 | A1 | 10001 | Snickers |
| EE100034442 | A2 | 10001 | Snickers |
| EE100034442 | A(n) | 10001 | Snickers |
+-------------+-----------+-------+----------+
I'm not quite sure I understand the question, but the sql you want is like;
Select machine1.machineid, setup.Selection, item.upc, item.name
From Machine_machine machine1 --Set alias for the table
Inner Join machine_setup setup on setup.machine_id = machine1.id --This looks like a link table to me
Inner Join item_item item on setup.item_id = item.id -- in your example this wouldn't link as item_id is 1 in the machine_setup
In your example the machine_setup item_id is set to 1, which means it wouldn't link to the item_item table. i'm assuming this is a mistake.
Let me know if you need more information.
Let's say I have this table, with both columns as primary keys, in mysql workbench and Innodb engine:
+--------+---------+
| grp | name |
+--------+---------+
| fish | lax |
| mammal | dog |
| mammal | bat |
| mammal | whale |
| bird | bat |
| bird | ostrich |
+--------+---------+
How can I add a column, behaving like this with grp column:
+--------+----+---------+
| grp | id | name |
+--------+----+---------+
| fish | 1 | lax |
| mammal | 2 | dog |
| mammal | 2 | cat |
| mammal | 2 | whale |
| bird | 3 | penguin |
| bird | 3 | ostrich |
+--------+----+---------+
Note that the actual table I want to alter is much bigger. Also note this is not what auto incrementing with MyISAM does and not what is asked here(but the answers could be helpful): How to auto increment on different foreign keys?
CREATE TABLE Groups (
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
grp VARCHAR...
PRIMARY KEY(id),
UNIQUE(grp)
) ENGINE=InnoDB
SELECT DISTINCT grp FROM YourTable;
That should give you the mapping between grp and id.
At this point, you should not generate a table with 3 columns (grp+id+name), but instead use the above Groups as a "normalization", which you seem to be doing. Then do
CREATE TABLE New LIKE YourTable;
ALTER TABLE New
ADD COLUMN id INT UNSIGNED NOT NULL,
DROP COLUMN grp;
# Note: if you have an index on grp, something else may need to be done.
INSERT INTO New
SELECT g.id, y.name
FROM Groups g
JOIN YourTable y ON y.grp = g.grp;
# At this point, verify that `New` has what you want. Then switch over:
RENAME TABLE YourTable TO Old, New TO YourTable;
DROP TABLE Old;
Edit I chose to create a new table rather than update the existing table -- because it will be (I think) considerably faster. With UPDATE, all the rows would need to be locked. With INSERT..SELECT, they are simply created.
I have the following table
SNo Value Item
where Sno is a column which exists in another table also. Right now , what I need is a self incrementing field which will go on incrementing if the value of sno is a constant and then get back to 0 and start incrementing again once the value of sno changes. IS there any way to do this?
Lets say I have four columns:
SNO |Value |Item | AUtoIncrementingField
1 344 a 0
1 345 b 1
1 346 c 2
2 568 d 0
So when I say insert into this table , and the value of SNO changes from whatr it originally was the value of the auto incrementing field should go back to 0. Is there any inbuilt way of doing this, or writing some code on top of mysql to achieve this. If not what other option do I have to uniquely identify each value/item belonging to a certain value of sno?
Whilst this doesn't help you on InnoDB, it's worth pointing out that MyISAM natively supports this functionality. As documented under Using AUTO_INCREMENT:
MyISAM Notes
For MyISAM 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. This is useful when you want to put data into ordered groups.
CREATE TABLE animals (
grp ENUM('fish','mammal','bird') NOT NULL,
id MEDIUMINT NOT NULL AUTO_INCREMENT,
name CHAR(30) NOT NULL,
PRIMARY KEY (grp,id)
) ENGINE=MyISAM;
INSERT INTO animals (grp,name) VALUES
('mammal','dog'),('mammal','cat'),
('bird','penguin'),('fish','lax'),('mammal','whale'),
('bird','ostrich');
SELECT * FROM animals ORDER BY grp,id;
Which returns:
+--------+----+---------+
| grp | id | name |
+--------+----+---------+
| fish | 1 | lax |
| mammal | 1 | dog |
| mammal | 2 | cat |
| mammal | 3 | whale |
| bird | 1 | penguin |
| bird | 2 | ostrich |
+--------+----+---------+
In this case (when the AUTO_INCREMENT column is part of a multiple-column index), AUTO_INCREMENT values are reused if you delete the row with the biggest AUTO_INCREMENT value in any group. This happens even for MyISAM tables, for which AUTO_INCREMENT values normally are not reused.