Mysql->autoincrementing related to an other field - mysql

I am stuck on a project design. One of the table has 1-M relation with users table. So it has a foreign key. Same field is also primary key.
Table as follows
Itemid:
Primarykey
Autoincrement
Useriditem:
Primarykey
Foreign key of id in users table
Itemname:
Not null
Values:
-----------------------------------------
| **ITEMID** | **USERID** | ITEMNAME |
-----------------------------------------
| 1 | 1 | fooooooo |
-----------------------------------------
| 2 | 1 | tinytext |
-----------------------------------------
| 3 | 1 | MediumText |
-----------------------------------------
| 4 | 2 | LARGEtext |
-----------------------------------------
| 5 | 2 | HUGETEXT |
-----------------------------------------
| 6 | 1 | BLOOOOOB |
-----------------------------------------
| 7 | 3 | 001010101 |
-----------------------------------------
This is the result of the current design. What i am wondering is that a way to make auto increment for each user separately.
Something like "Autoincrement item id GROUP BY user id"
-----------------------------------------
| **ITEMID** | **USERID** | ITEMNAME |
-----------------------------------------
| 1 | 1 | fooooooo |
-----------------------------------------
| 2 | 1 | tinytext |
-----------------------------------------
| 3 | 1 | MediumText |
-----------------------------------------
| 1 | 2 | LARGEtext |
-----------------------------------------
| 2 | 2 | HUGETEXT |
-----------------------------------------
| 4 | 1 | BLOOOOOB |
-----------------------------------------
| 1 | 3 | 001010101 |
-----------------------------------------
Is there a way to do this using mysql?

You want something like this:
Demo
CREATE TRIGGER item_id_auto_inc
BEFORE INSERT ON items
FOR EACH ROW
BEGIN
SET NEW.item_id := (SELECT CASE WHEN ISNULL(MAX(item_id)) THEN 0 ELSE MAX(item_id) END +1 FROM items WHERE user_id=NEW.user_id);
END
//

I dont know what happens when multiple users execute queries but i think i managed to narrow down the algorithm.
how to "insert into table (col1, col2) values (select max(id) from table2, select id from table3); "?
INSERT INTO table VALUES (
(SELECT (MAX(itemid)+1)
FROM table
WHERE userid = 'theid') , 'theid' , 'foo1');
Can this solve the simultaneous execution by multiple user problem.

The safer way to do this is taking into account that your application can get hit by more than 1 user at any given time
START TRANSACTION;
Insert into table A
Select Last inserted id from table A using Last_Insert_ID()
Update table B
COMMIT;
At least you are guaranteed to get this last inserted id from table A into table B.

Related

MySQL Order by id, unless the record has a parent_id

I'm using Laravel (and MySQL of course) to build a pages module, a page can have 1 parent
This is my current data, and using order_by="id" it's also returned like this.
+----+-----------+
| id | parent_id |
+----+-----------+
| 1 | NULL |
| 2 | NULL |
| 3 | 1 |
| 4 | 1 |
+----+-----------+
Now I'm wondering if it's possible to have a result set where the children are ordered underneath their parent. Which would render the following result
+----+-----------+
| id | parent_id |
+----+-----------+
| 1 | NULL |
| 3 | 1 |
| 4 | 1 |
| 2 | NULL |
+----+-----------+
Thoughts
Maybe it is possible to generate an order_by query that orders by id, but assigns a temporary id in a temp column, in between the others, in case the row has a parent_id?
So ideally the 2 children (3, 4) of the parent (1) are shown just below it.
You can use coalescefunction:
ORDER BY coalesce(`parent_id`,`id`),`parent_id` is not null
P.S. ,parent_id is not null is needed for the case even (2,1) inserted instead of (2,null) in the order of VALUES(2,1),(1,null),(3,1),(4,1)(special thanks to #splash58)
Demo

Get rows based on a condition that is dependent on the table and not solely on the row

Let's say I have a table with two (indexed) columns: document IDs and the words the document contains.
____________________
__docID__|__Word___|
1 | it |
1 | rains |
2 | this |
2 | is |
2 | cold |
3 | it |
3 | is |
3 | snowing |
So there are three documents represented in the table:
it rains, this is cold, it is snowing
How I can get the table efficiently that contains all the rows of those documents that contain a certain word, let's say Word = 'it':
____________________
__docID__|__Word___|
1 | it |
1 | rains |
3 | it |
3 | is |
3 | snowing |
Can the query be something like:
SELECT * FROM table
WHERE (docID = this.docID, Word = 'it') is in table
You can use this.
select
*
from
`some_table`
where `docID` in (select `docID` from `some_table` where `Word` = 'it');

MySQL insert skipped IDs

I have a mysql table which has two columns, id and value.
id(auto_increment primary key)
value(varchar 255)
insert into table columns(`id`,`value`)VALUES(,'something1');
insert into table columns(`id`,`value`)VALUES(,'something2');
output
+----+---------------+
| id | value |
+----+---------------+
| 1 | something1 |
| 2 | something2 |
+----+---------------+
Now Inserting one value again
insert into table columns(`id`,`value`)VALUES(8,'something8');
Updated Table
+----+---------------+
| id | value |
+----+---------------+
| 1 | something1 |
| 2 | something2 |
| 8 | something8 |
+----+---------------+
Now I am inserting one value again
insert into table columns(`id`,`value`)VALUES(,'something');
Final Output
+----+---------------+
| id | value |
+----+---------------+
| 1 | something1 |
| 2 | something2 |
| 8 | something8 |
| 9 | something |
+----+---------------+
But I want the final output like this
+----+---------------+
| id | value |
+----+---------------+
| 1 | something1 |
| 2 | something2 |
| 8 | something8 |
| 3 | something |
+----+---------------+
Now id is 3 and further insertion will create id 4,5,6,7,9 and so on.
Is there any way to get achieve this ?
I know it is old post but mybie it will help someone :)
I am afraid it cannot be done automatically, however, I solved it to my client, maybe some of you could find it useful:
DECLARE FirstEmptyId int;
SELECT l.id +1 AS
START
FROM TableName AS l
LEFT OUTER JOIN TableName AS r ON l.id +1 = r.id
WHERE r.id IS NULL
LIMIT 1 INTO FirstEmptyId;
Insert Into TableName (Id..) Values (FirstEmptyId...)
STILL, YOU HAVE TO MIND THAT IT IS NOT ADVISABLE TO INSERT ID VALUE OTHER WAY THAN BY AUTOINCREMENT IT AND THERE IS A REASON FOR THAT :)
Consider creating the second column just for performance purposes.
Good luck fellow coders!

Distinct order-number sequence for every customer

I have table of orders. Each customer (identified by the email field) has his own orders. I need to give a different sequence of order numbers for each customer. Here is example:
----------------------------
| email | number |
----------------------------
| test#com.com | 1 |
----------------------------
| example#com.com | 1 |
----------------------------
| test#com.com | 2 |
----------------------------
| test#com.com | 3 |
----------------------------
| client#aaa.com | 1 |
----------------------------
| example#com.com | 2 |
----------------------------
Is possible to do that in a simple way with mysql?
If you want update data in this table after an insert, first of all you need a primary key, a simple auto-increment column does the job.
After that you can try to elaborate various script to fill the number column, but as you can see from other answer, they are not so "simple way".
I suggest to assign the order number in the insert statement, obtaining the order number with this "simpler" query.
select coalesce(max(`number`), 0)+1
from orders
where email='test1#test.com'
If you want do everything in a single insert (better for performance and to avoid concurrency problems)
insert into orders (email, `number`, other_field)
select email, coalesce(max(`number`), 0) + 1 as number, 'note...' as other_field
from orders where email = 'test1#test.com';
To be more confident about not assign at the same customer two orders with the same number, I strongly suggest to add an unique constraint to the columns (email,number)
create a column order_number
SELECT #i:=1000;
UPDATE yourTable SET order_number = #i:=#i+1;
This will keep incrementing the column value in order_number column and will start right after 1000, you can change the value or even you can even use the primary key as the order number since it is unique all the time
I think one more need column for this type of out put.
Example
+------+------+
| i | j |
+------+------+
| 1 | 11 |
| 1 | 12 |
| 1 | 13 |
| 2 | 21 |
| 2 | 22 |
| 2 | 23 |
| 3 | 31 |
| 3 | 32 |
| 3 | 33 |
| 4 | 14 |
+------+------+
You can get this result:
+------+------+------------+
| i | j | row_number |
+------+------+------------+
| 1 | 11 | 1 |
| 1 | 12 | 2 |
| 1 | 13 | 3 |
| 2 | 21 | 1 |
| 2 | 22 | 2 |
| 2 | 23 | 3 |
| 3 | 31 | 1 |
| 3 | 32 | 2 |
| 3 | 33 | 3 |
| 4 | 14 | 1 |
+------+------+------------+
By running this query, which doesn't need any variable defined:
SELECT a.i, a.j, count(*) as row_number FROM test a
JOIN test b ON a.i = b.i AND a.j >= b.j
GROUP BY a.i, a.j
Hope that helps!
You can add number using SELECT statement without adding any columns in table orders.
try this:
SELECT email,
(CASE email
WHEN #email
THEN #rownumber := #rownumber + 1
ELSE #rownumber := 1 AND #email:= email END) as number
FROM orders
JOIN (SELECT #rownumber:=0, #email:='') AS t

MySQL copy column from different tables, insert at top of table

I'm trying to merge a couple tables together to consolidate the data, but when I try to insert a column from one table to the other, the query I'm using inserts the records after the last currently existing record in the table. There are a ton of questions about duplicating columns, but they all seem to be starting with an empty table.
INSERT INTO newTable( newColumn ) SELECT oldColumn FROM oldTable
How do I modify this query to insert the rows at the beginning of the table instead of the end?
Visual representation of what is happening (left) vs. what I want to happen (right):
+--------+--------+------------+ +--------+--------+------------+
| ID | Column | newColumn | | ID | Column | newColumn |
+--------+--------+------------+ +--------+--------+------------+
| 1 | 12345 | | | 1 | 12345 | 12345 |
| 2 | 12345 | | | 2 | 12345 | 12345 |
| 3 | 12345 | | | 3 | 12345 | 12345 |
| 4 | | 12345 | +--------+--------+------------+
| 5 | | 12345 |
| 6 | | 12345 |
+--------+--------+------------+
As mentioned in the comments you need an UPDATE statement not an INSERT statement:
UPDATE newTable
JOIN oldTable
ON newTable.id = oldTable.id
SET newcolumn = oldcolumn;
A tested example may be seen here: http://sqlfiddle.com/#!2/77724/1