Using code to increment values in a column - mysql

I am trying to use a simple code to increment only the values in the “chat_id” column of a table.
For the table lz_chat_archive_dup1, the column “chat_id” is has empty strings (no values). This is the partial excerpt of the table :
mysql> select chat_id, fullname from lz_chat_archive_dup1 LIMIT 5;
+---------+--------------+
| chat_id | fullname |
+---------+--------------+
| | Yw |
| | Shah |
| | Sunny Duhel |
| | Leong Zi Yin |
| | Mohd Nasir |
+---------+--------------+
5 rows in set (0.00 sec)
I tried to insert a value for the name “Yw” like this and it worked :
mysql> UPDATE lz_chat_archive_dup1 SET chat_id = '383933' where fullname = 'Yw';
Query OK, 1 row affected (0.01 sec)
Rows matched: 1 Changed: 1 Warnings: 0
So now the table is like this :
mysql> select chat_id, fullname from lz_chat_archive_dup1 LIMIT 5;
+---------+--------------+
| chat_id | fullname |
+---------+--------------+
| 383933 | Yw |
| | Shah |
| | Sunny Duhel |
| | Leong Zi Yin |
| | Mohd Nasir |
+---------+--------------+
5 rows in set (0.00 sec)
However, the number of rows in this table is 2589, and for me to do it one by one is tedious and time consuming :
mysql> select count(*) from lz_chat_archive_dup1;
+----------+
| count(*) |
+----------+
| 2589 |
+----------+
1 row in set (0.00 sec)
I thought I could use a code something like this to update/increment only that one column, but I don’t think this is the correct syntax for MySQL. Can you please help to correct the code to customize it to work in my situation :
DECLARE #counter int
SET #counter = 383933
UPDATE #lz_chat_archive_dup1
SET #counter = counter = #counter + 1
So with this code, what I am trying to achieve is increment the chat_id column so that the next value is always 1 integer higher than the previous one. So the first row is 383933, the next one should be 383934, 383935, 383936,…etc etc.
The table has > 2000 rows, so this is an excerpt of it :
mysql> select time, endtime, chat_id from lz_chat_archive_dup1 LIMIT 20;
+------------+------------+---------+
| time | endtime | chat_id |
+------------+------------+---------+
| 1594948770 | 1594948928 | 383933 |
| 1594950285 | 1594950542 | |
| 1594950708 | 1594951085 | |
| 1594953554 | 1594955581 | |
| 1594955956 | 1594956551 | |
| 1595215646 | 1595218410 | |
| 1595215648 | 1595216044 | |
| 1595216110 | 1595216138 | |
| 1595220816 | 1595221144 | |
| 1595221046 | 1595221584 | |
| 1595221448 | 1595221505 | |
| 1595222302 | 1595222653 | |
| 1595236468 | 1595236848 | |
| 1595236954 | 1595237033 | |
| 1595293418 | 1595293589 | |
| 1595303280 | 1595304388 | |
| 1595303410 | 1595303822 | |
| 1595303675 | 1595303986 | |
| 1595304153 | 1595306613 | |
| 1595304878 | 1595304995 | |
+------------+------------+---------+
20 rows in set (0.00 sec)
mysql>

Here is an approach using a user variable:
set #rn = 383933;
update #lz_chat_archive_dup1
set chat_id = (select #rn := #rn + 1)
order by name;
This will assign an incrementingn number to each row, following the alphabetical order of name. If there are ties, it is undefined which name will get which number (a reason why you should have a primary key column in your table).

Assuming the names are unique, you could use a join:
update lz_chat_archive_dup1 cad join
(select cad2.*, row_number() over () as seqnum
from lz_chat_archive_dup1 cad2
) cad2
on cad2.name = cad.name
set count = seqnum + 383933;
I think this might be the recommended approach in MySQL 8+. (The statement on the deprecation of variables is a little vague on whether it would apply to UPDATE.)
You can also use variables. The problem with your statement is:
SET #counter = counter = #counter + 1
This is not even setting the column in the table! It is setting a variable. Use := to set parameters. And I strongly recommend parentheses. So, you can do:
DECLARE #counter int;
SET #counter = 383933;
UPDATE #lz_chat_archive_dup1
SET counter = (#counter := #counter + 1);
Or, in a single statement:
UPDATE #lz_chat_archive_dup1 cad CROSS JOIN
(SELECT #counter := 383933) params
SET cad.counter = (#counter := #counter + 1);

If you can live with numbers starting from 1, following the alphabetic order of your fullname column, you can try with a helper table to run the update:
CREATE TABLE updtab
AS
SELECT
ROW_NUMBER() OVER(ORDER BY fullname) AS chat_id
, fullname
FROM lz_chat_archive_dup1;
Then , run the update:
UPDATE lz_chat_archive_dup1
SET chat_id = (
SELECT chat_id
FROM updtab
WHERE updtab.fullname=lz_chat_archive_dup1.fullname
)
;

Related

mysql query returns empty set when data is there

+----+---------+--------------------+----------+------+---------------------+---------+-------------+------------+----------+
| id | pname | pmail | pgender | page | pdetails | pnumber | ddepartment | date | time |
+----+---------+--------------------+----------+------+---------------------+---------+-------------+------------+----------+
| 1 | karuna | karuna#gmail.com | female | 21 | hfsdh gfhdf shdh | 2332 | Surgeon | 2018-05-15 | 16:00:00 |
+----+---------+--------------------+----------+------+---------------------+---------+-------------+------------+----------+
This is my database table appointment.
Whenever I execute first two queries, they run perfectly
select * from appointment;(execute )
select * from appointment where pname = 'karuna';(execute)
but when I try to execute these two queries, the result I get is empty set
select *from appointment where pmail='karuna#gmail.com';(empty set (0.00 sec))
select *from appointment where ddepartment='Surgeon';(empty set (0.00 sec))

mysql query, different performance between = and IN

why there is this difference of time execution between these two queries even if they retrieve the same amount of rows from the same table?
select cognome, nome, lingua, count(*)
from archivio.utente
where cognome in ('rossi','pecchia','pirono')
group by cognome, nome, lingua;
…
…
…
| Rossi | Mario | it | 1 |
| Pironi | Luigi | it | 1 |
| Pecchia | Fabio | it | 1 |
+----------------------+---------+--------+----------+
779 rows in set (0.03 sec)
select cognome, nome, lingua, count(*)
from archivio.utente
where nome='corrado'
group by cognome, nome, lingua;
…
…
…
| Rossi | Mario | it | 1 |
| Pironi | Luigi | it | 1 |
| Pecchia | Fabio | it | 1 |
+----------------------+---------+--------+----------+
737 rows in set (0.47 sec)
from mysql documentation :
https://dev.mysql.com/doc/refman/5.7/en/explain-output.html#explain-join-types
when we use in
Only rows that are in a given range are retrieved, using an index to select the rows.
The key column in the output row indicates which index is used.
when we use =
A full table scan is done for each combination of rows
So in one case all lines are retrieved and compared, in another case just a range.

MySQL: How do you add new id column to the table, group by the old column?

I am trying to add column new_id to the table in MySQL Workbench, but I want this new_id to be GROUP BY the old_id.
I tried the code below. The new_id is automatic increasing, but it is not group by old_id.
ALTER TABLE candidate
ADD COLUMN new_id int not null auto_increment UNIQUE FIRST,
ADD PRIMARY KEY(old_id, new_id);
Below is what I got:
+----------+--------+
| old_id | new_id |
+----------+--------+
| 00132004 | 1 |
| 00132004 | 2 |
| 00132004 | 3 |
| 00132004 | 4 |
| 00118685 | 5 |
| 00118685 | 6 |
| J99999 | 7 |
| J99999 | 8 |
| J99988 | 9 |
| J99987 | 10 |
+----------+--------+
But this is what I want to get:
+----------+--------+
| old_id | new_id |
+----------+--------+
| 00132004 | 1 |
| 00132004 | 1 |
| 00132004 | 1 |
| 00132004 | 1 |
| 00118685 | 2 |
| 00118685 | 2 |
| J99999 | 3 |
| J99999 | 3 |
| J99988 | 4 |
| J99987 | 5 |
+----------+--------+
What am I missing here....?
Thank you!!!
Your new requirement for new_id will not work making that column auto increment, because then the values will not be unique or incremental.
What you are looking for is something called the dense rank. MySQL does not have built in support for this, but you can simulate it using session variables:
SET #dense_rank = 0;
SET #old_id = NULL;
SELECT
#dense_rank:=CASE WHEN #old_id = old_id
THEN #dense_rank ELSE #dense_rank + 1 END AS dr,
#old_id:=old_id AS old_id,
new_id
FROM candidate
ORDER BY new_id
Note that because MySQL does not support any clean way of automatically having a dense rank maintained, a SELECT query might be your best long term option. This way, you can just compute the dense rank from the latest data whenever you need it, without needing to worry about maintaining it in your actual table.
Output:
Demo here:
Rextester
What you want can (sadly) not be done with an auto-increment column.
An alternative solution could be:
CREATE TABLE mytab (new_id int not null auto_increment,
old_id VARCHAR(200),
FOREIGN KEY old_id (old_id) REFERENCES candidate(old_id));
CREATE UNIQUE INDEX old_id_idx ON mytab(old_id);
This guarantees unique old_ids and gives you a unique new_id in return. You can now join this new_id against the candidate table with an INNER JOIN and get your desired result.
Add the column, then set it using update:
set #old_id = '', #rn = 0;
update candidate
set new_id = if(#old_id = old_id, #rn,
if(#old_id := old_id, #rn := #rn + 1, #rn := #rn + 1)
)
order by old_id;

Mysql with GROUP_CONCAT in subselect

I have problem with subselect in mysql. In table restaurants I have field "sup" where I have IDs separated by comma.
Basic select:
mysql> select name, sup from restaurants LIMIT 5;
+-------------------------------------+---------+
| name | sup |
+-------------------------------------+---------+
| Pizzerija in špagetarija Buf | 2,14,18 |
| EJGA - KAVARNA - RESTAVRACIJA - PUB | 11,17 |
| Restavracija Center | 5,22 |
| Restavracija Viola | 5,13,17 |
| Gostilna Anderlič | 5,17 |
+-------------------------------------+---------+
5 rows in set (0.00 sec)
I want to know the field "SI" from table suply for IDs in sup.restaurants table. So my select for that is:
mysql> SELECT GROUP_CONCAT(suply.SI SEPARATOR ', ') FROM `suply` WHERE id IN (2,14,18);
+---------------------------------------+
| GROUP_CONCAT(suply.SI SEPARATOR ', ') |
+---------------------------------------+
| Italijanska, Špagetarija, Picerija |
+---------------------------------------+
1 row in set (0.00 sec)
So I wrote select with subselct but doesn't work well:
mysql> SELECT restaurants.name,
-> (SELECT GROUP_CONCAT(suply.SI SEPARATOR ', ') FROM `suply` WHERE id IN (restaurants.sup)) AS hrana
-> FROM restaurants
-> LIMIT 5;
+-------------------------------------+--------------------+
| name | hrana |
+-------------------------------------+--------------------+
| Pizzerija in špagetarija Buf | Italijanska |
| EJGA - KAVARNA - RESTAVRACIJA - PUB | Mednarodna kuhinja |
| Restavracija Center | Slovenska domača |
| Restavracija Viola | Slovenska domača |
| Gostilna Anderli? | Slovenska domača |
+-------------------------------------+--------------------+
5 rows in set (0.00 sec)
Why in this select I get just first string?
Use FIND_IN_SET function to search in comma separated list
WHERE FIND_IN_SET(id, restaurants.sup)

SELECT and UPDATE same rows in MYSQL stored procedure

I'm working on a application for which I need to read m rows at a time out of total 'N' rows where m < N. Every time I read 'm' rows I have to set their status as read in the same table.
For example consider following table
+------+-------------------------+--------------------------+----------+-------+---------+------+
| ID | from_email_address | to_email_address | subject | body | inqueue | sent |
+------+-------------------------+--------------------------+----------+-------+---------+------+
| 1 | 0120sushil#gmail.com | kumar.sushil#outlook.com | Subject1 | Body1 | 0 | 0 |
| 2 | 0120ksushil#gmail.com | kumar.sushil#outlook.com | Subject1 | Body1 | 0 | 0 |
| 3 | shivaseth1#gmail.com | kumar.sushil#outlook.com | Subject1 | Body1 | 0 | 0 |
| 4 | shivaseth1#gmail.com | amanrajg#outlook.com | Subject1 | Body1 | 0 | 0 |
| 5 | shivamprakash#gmail.com | amanrajg#outlook.com | Subject1 | Body1 | 0 | 0 |
| 6 | shivamprakash#gmail.com | poorvanagpal#outlook.com | Subject1 | Body1 | 0 | 0 |
| 7 | shivankgupta#gmail.com | poorvanagpal#outlook.com | Subject1 | Body1 | 0 | 0 |
+------+-------------------------+--------------------------+----------+-------+---------+------+
I want to read lets say 3 rows at a time and once I have read the rows I want to set inqueue status of those rows as 1.
I can use following query in stored procedure to select the rows
select * from EmailQueue where inqueue=1 LIMIT 3
After this how to update the same rows and set their inqueue to 1.
EDIT
Here is the stored procedure I created which is giving some error.
DELIMITER $$
DROP PROCEDURE IF EXISTS GetUnsentMails;
CREATE PROCEDURE GetUnsentMails()
BEGIN
START TRANSACTION;
CREATE TEMPORARY TABLE temp_EmailQueue AS SELECT * FROM EmailQueue WHERE inqueue = 0 LIMIT 5 FOR UPDATE;
UPDATE EmailQueue SET inqueue=1 where id in (SELECT id from temp_EmailQueue) AND inqueue = 0;
COMMIT;
END
It gives following error on calling
ERROR 1746 (HY000): Can't update table 'emailqueue' while 'temp_EmailQueue' is being created.
Suggesting to use Transaction and "SELECT FOR UPDATE" to fulfill your requirements.
Please refer following links for the examples:
MySQL 'select for update' behaviour
http://dev.mysql.com/doc/refman/5.0/en/innodb-locking-reads.html
http://www.sqlines.com/mysql/how-to/select-update-single-statement-race-condition
UPDATE - Added the QUERY EXAMPLE:
Example:
.......
#Before starting procedure
.......
START TRANSACTION;
CREATE TEMPORARY TABLE zzz_EmailQueue AS SELECT * FROM EmailQueue WHERE inqueue=1 LIMIT 3 FOR UPDATE;
.....
.....
#Section for other activities....
.....
.....
UPDATE EmailQueue SET inqueue=<<New_Value>> WHERE id IN (SELECT id FROM zzz_EmailQueue) AND inqueue=1;
COMMIT;
.......
#Remaining lines of Prodecure
.......
Update **
**Try with following method:
DECLARE v_EmailQueue_ID DOUBLE;
SELECT ID INTO v_EmailQueue_ID FROM EmailQueue WHERE inqueue = 0 LIMIT 1 FOR UPDATE;
UPDATE EmailQueue SET inqueue=1 WHERE id=v_EmailQueue_ID AND inqueue = 0;