mysql middle row deleted and fix primary key with arranging order - mysql

i have table with id that is primary key activated with 20 data inserted . and i have deleted row 15,16,17 and how can i arrange increasing order from 1 to 17
CREATE TABLE `cart` (
`id` int(255) NOT NULL,
`productname` varchar(255) NOT NULL,
`productquantity` varchar(255) NOT NULL,
`productsize` varchar(255) NOT NULL,
`productprice` varchar(255) NOT NULL
)

Determine row_number for each row, in an increasing order of id, starting from 1 in a Derived Table.
Join this Derived table with your main table, and update the id value to be equal to row_number. This will reset all the id values to start from 1 (with no gaps).
Try (works for all MySQL versions):
UPDATE your_table AS t1
JOIN
(
SELECT #row_no := #row_no + 1 AS row_num,
id
FROM your_table
JOIN (SELECT #row_no := 0) AS init
ORDER BY id
) AS dt ON dt.id = t1.id
SET t1.id = dt.row_num;
DB Fiddle DEMO

Related

Update table increasing every row by 1 from max

I'm trying to increase several rows order field by one while taking into account max value of that field.
CREATE TABLE IF NOT EXISTS `jobs`(
`id` INT(11) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(128) NOT NULL,
`order` INT(11) NOT NULL DEFAULT 0,
PRIMARY KEY(`id`));
INSERT INTO `jobs`(`name`) VALUES("John"),("Steven"),("Marie"),("Clair"),("Richard"),("Rober"),("Barbara")
UPDATE
`jobs` AS `j1`,
(SELECT MAX(`order`) AS `max` FROM jobs) AS `j2`
SET `j1`.`order` = `j2`.`max` + 1
WHERE `j1`.`id` > 4
It sets rows of Richard, Rober and Barbara to 1 and I want to be 1,2,3 and if I would execute it again I want them to be 4,5,6
I know It would be perfect if the column order would be auto_increment / unique but it can't be in this case.
If you can use user defined variables then you can do so
UPDATE
`jobs` AS `j1`
cross join (
select #r:= (SELECT MAX(`order`) AS `max` FROM jobs)
) t
SET `j1`.`order` = #r:= #r + 1
WHERE `j1`.`id` > 4
Demo for single update
Demo for 2 times update

Mysql create view with count clause

In my db I've a table (t1) with this structure
CREATE TABLE IF NOT EXISTS 't1' (
'id_ric' int(11) NOT NULL AUTO_INCREMENT,
'id_tipoins' decimal(1,0) NOT NULL,
'datains' timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY ('id_ric')
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
I create a view to count all record grouped by id_user in this way
CREATE VIEW view_users_app
AS
SELECT id_user, MAX(datains) last_datains, COUNT(*) totalCount
FROM t1
GROUP BY id_user
Now I'd like also count where id_tipoins = 1 and id_tipoins = 2 (grouped by id_user).
It's possible to do? How could I do this? Thanks
CREATE VIEW view_users_app
AS
SELECT id_user,
MAX(datains) last_datains,
COUNT(*) totalCount,
sum(id_tipoins = 1) as p1,
sum(id_tipoins = 2) as p2
FROM t1
GROUP BY id_user

UPDATE tableName, (SELECT #id := 0) dm SET sale_id = (#id := #id 1)

I have the following table in my database:
CREATE TABLE IF NOT EXISTS `candidate` (
`candidate_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`roll_no` int(10) unsigned NOT NULL,
`candidate_name` varchar(255) DEFAULT NULL,
`batch_id` int(10) unsigned NOT NULL,
PRIMARY KEY (`candidate_id`),
KEY `candidate_name` (`candidate_name`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT;
What I need to do is to assign roll_no to candidates in a particular batch. i.e. there roll_no will start from 1 for each batch_id. *(Needless to say there are thousands of candidates per batch or batch_id)*. The value of roll_no field is 0 by default.
What I tried doing:
UPDATE candidate c, (SELECT #id := 0) serial
SET roll_no = (#id := #id + 1)
WHERE c.batch_id = 5
ORDER BY c.candidate_name ASC
Resulting in: Incorrect use of UPDATE and ORDER BY
If I omit the ORDER BY clause, it works fine, but I need to assign the roll_no to candidates according to the ascending order of their names
Is there any way of achieving what I am trying ... and most importantly, am I clear?
Thanking you all in advance.
Will this working?
SET #id := 0;
UPDATE candidate c
SET roll_no = (#id := #id + 1)
WHERE batch_id = 5
ORDER BY candidate_name ASC;
Eureka!! This did the trick
UPDATE candidate c
JOIN (SELECT candidate_id, candidate_name FROM candidate ORDER BY candidate_name ASC) co ON (c.candidate_id = co.candidate_id)
JOIN (SELECT #a:=0) dm
SET roll_no = (#a:=#a+1)
WHERE batch_id = 5
Got some idea from
update+order by in same query mysql
Erik Lukman, Thanks for your response.

Need help creating SQL query

I have thus two tables:
CREATE TABLE `workers` (
`id` int(7) NOT NULL AUTO_INCREMENT,
`number` int(7) NOT NULL,
`percent` int(3) NOT NULL,
`order` int(7) NOT NULL,
PRIMARY KEY (`id`)
);
CREATE `data` (
`id` bigint(15) NOT NULL AUTO_INCREMENT,
`workerId` int(7) NOT NULL,
PRIMARY KEY (`id`)
);
I want to return the first worker (order by order ASC) that his number of rows in the table data times percent(from table workers) /100 is smaller than number(from table workers.
I have tried this query:
SELECT workers.id, COUNT(data.id) AS `countOfData`
FROM `workers` as workers, `data` as data
WHERE data.workerId = workers.id
AND workers.percent * `countOfData` < workers.number
LIMIT 1
But I get the error:
#1054 - Unknown column 'countOfData' in 'where clause'
This should work:
SELECT A.id
FROM workers A
LEFT JOIN (SELECT workerId, COUNT(*) AS Quant
FROM data
GROUP BY workerId) B
ON A.id = B.workerId
WHERE (COALESCE(Quant,0) * `percent`)/100 < `number`
ORDER BY `order`
LIMIT 1
You could calculate the number of rows per worker in a subquery. The subquery can be joined to the worker table. If you use a left join, a worker with no data rows will be considered:
select *
from workers w
left join
(
select workerId
, count(*) as cnt
from data
group by
workerId
) d
on w.id = d.workerId
where coalesce(d.cnt, 0) * w.percent / 100 < w.number
order by
w.order
limit 1

Super slow query with CROSS JOIN

I have two tables named table_1 (1GB) and reference (250Mb).
When I query a cross join on reference it takes 16hours to update table_1 .. We changed the system files EXT3 for XFS but still it's taking 16hrs.. WHAT AM I DOING WRONG??
Here is the update/cross join query :
mysql> UPDATE table_1 CROSS JOIN reference ON
-> (table_1.start >= reference.txStart AND table_1.end <= reference.txEnd)
-> SET table_1.name = reference.name;
Query OK, 17311434 rows affected (16 hours 36 min 48.62 sec)
Rows matched: 17311434 Changed: 17311434 Warnings: 0
Here is a show create table of table_1 and reference:
CREATE TABLE `table_1` (
`strand` char(1) DEFAULT NULL,
`chr` varchar(10) DEFAULT NULL,
`start` int(11) DEFAULT NULL,
`end` int(11) DEFAULT NULL,
`name` varchar(255) DEFAULT NULL,
`name2` varchar(255) DEFAULT NULL,
KEY `annot` (`start`,`end`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 ;
CREATE TABLE `reference` (
`bin` smallint(5) unsigned NOT NULL,
`name` varchar(255) NOT NULL,
`chrom` varchar(255) NOT NULL,
`strand` char(1) NOT NULL,
`txStart` int(10) unsigned NOT NULL,
`txEnd` int(10) unsigned NOT NULL,
`cdsStart` int(10) unsigned NOT NULL,
`cdsEnd` int(10) unsigned NOT NULL,
`exonCount` int(10) unsigned NOT NULL,
`exonStarts` longblob NOT NULL,
`exonEnds` longblob NOT NULL,
`score` int(11) DEFAULT NULL,
`name2` varchar(255) NOT NULL,
`cdsStartStat` enum('none','unk','incmpl','cmpl') NOT NULL,
`cdsEndStat` enum('none','unk','incmpl','cmpl') NOT NULL,
`exonFrames` longblob NOT NULL,
KEY `chrom` (`chrom`,`bin`),
KEY `name` (`name`),
KEY `name2` (`name2`),
KEY `annot` (`txStart`,`txEnd`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 ;
You should index table_1.start, reference.txStart, table_1.end and reference.txEnd table fields:
ALTER TABLE `table_1` ADD INDEX ( `start` ) ;
ALTER TABLE `table_1` ADD INDEX ( `end` ) ;
ALTER TABLE `reference` ADD INDEX ( `txStart` ) ;
ALTER TABLE `reference` ADD INDEX ( `txEnd` ) ;
Cross joins are Cartesian Products, which are probably one of the most computationally expensive things to compute (they don't scale well).
For each table T_i for i = 1 to n, the number of rows generated by crossing tables T_1 to T_n is the size of each table multiplied by the size of each other table, ie
|T_1| * |T_2| * ... * |T_n|
Assuming each table has M rows, the resulting cost of computing the cross join is then
M_1 * M_2 ... M_n = O(M^n)
which is exponential in the number of tables involved in the join.
I see 2 problems with the UPDATE statement.
There is no index for the End fields. The compound indexes (annot) you have will be used only for the start fields in this query. You should add them as suggested by Emre:
ALTER TABLE `table_1` ADD INDEX ( `end` ) ;
ALTER TABLE `reference` ADD INDEX ( `txEnd` ) ;
Second, the JOIN may (and probably does) find many rows of table reference that are related to a row of table_1. So some (or all) rows of table_1 that are updated, are updated many times. Check the result of this query, to see if it is the same as your updated rows count (17311434):
SELECT COUNT(*)
FROM table_1
WHERE EXISTS
( SELECT *
FROM reference
WHERE table_1.start >= reference.txStart
AND table_1.`end` <= reference.txEnd
)
There can be other ways to write this query but the lack of a PRIMARY KEY on both tables makes it harder. If you define a primary key on table_1, try this, replacing id with the primary key.
Update: No, do not try it on a table with 34M rows. Check the execution plan and try with smaller tables first.
UPDATE table_1 AS t1
JOIN
( SELECT t2.id
, r.name
FROM table_1 AS t2
JOIN
( SELECT name, txStart, txEnd
FROM reference
GROUP BY txStart, txEnd
) AS r
ON t2.start >= r.txStart
AND t2.`end` <= r.txEnd
GROUP BY t2.id
) AS good
ON good.id = t1.id
SET t1.name = good.name;
You can check the query plan by running EXPLAIN on the equivalent SELECT:
EXPLAIN
SELECT t1.id, t1.name, good.name
FROM table_1 AS t1
JOIN
( SELECT t2.id
, r.name
FROM table_1 AS t2
JOIN
( SELECT name, txStart, txEnd
FROM reference
GROUP BY txStart, txEnd
) AS r
ON t2.start >= r.txStart
AND t2.`end` <= r.txEnd
GROUP BY t2.id
) AS good
ON good.id = t1.id ;
Try this:
UPDATE table_1 SET
table_1.name = (
select reference.name
from reference
where table_1.start >= reference.txStart
and table_1.end <= reference.txEnd)
Somebody already offered you to add some indexes. But I think the best performance you may get with these two indexes:
ALTER TABLE `test`.`time`
ADD INDEX `reference_start_end` (`txStart` ASC, `txEnd` ASC),
ADD INDEX `table_1_star_end` (`start` ASC, `end` ASC);
Only one of them will be used by MySQL query, but MySQL will decide which is more useful automatically.