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

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.

Related

mysql middle row deleted and fix primary key with arranging order

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

MySql update with different values a column for duplicate columns

I have a table like this
CREATE TABLE IF NOT EXISTS users_groups(
id INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
user_id INT(11) UNSIGNED NOT NULL,
name VARCHAR(250) NOT NULL,
is_deleted BOOLEAN NOT NULL DEFAULT false,
creation_date DATETIME NOT NULL,
last_modification_date DATETIME NOT NULL,
PRIMARY KEY (id)
);
And I would like to turn the columns (user_id, name) as unique, but the problem I have is that I already have duplicates in that columns. In some cases the columns are repeated many times.
I would like to write a query to update the duplicates rows concatenating some value in the name, for example concatening '*' for the first duplicate '**' for the second duplicate, and so on.
Is this possible writing a query?
I can get the group that I want to modify, but I am not sure if it is possible to achieve what I want with mysql
select users_groups.id, users_groups.user_id, users_groups.name
from users_groups
inner join (select user_id, name, count(*) from users_groups group by user_id, name having count(*) > 1) as u on u.user_id = users_groups.user_id
where users_groups.name = u.name;
Try this.
SET #prev_user_id := '';
SET #prev_name := '';
SET #cnt := 0;
select s.id, s.user_id, s.name
from
(
select
users_groups.id,
IF(#prev_user_id <> users_groups.user_id OR #prev_name <> users_groups.name, #cnt := 0, #cnt := #cnt + 1) AS cnt,
CONCAT(users_groups.user_id, REPEAT('*', #cnt)) AS user_id,
CONCAT(users_groups.name, REPEAT('*', #cnt)) AS name,
#prev_user_id := users_groups.user_id,
#prev_name := users_groups.name
from
users_groups
) s
Check here:
http://sqlfiddle.com/#!9/6d553/10
I'm not sure if this helps, but you can make a column unique without it having to be the primary key of that table.
For example:
CREATE TABLE user (
user_id NOT NULL,
firstname varchar(255) NOT NULL,
UNIQUE (firstname)
)
Or the following statement which creates a unique constraint across multiple columns.
CREATE TABLE user (
user_id NOT NULL,
firstname varchar(255) NOT NULL,
CONSTRAINT constraint_name UNIQUE (user_id, firstname)
)
Also, I'm not entirely sure why you would want to identify duplicates. It's good practice to avoid duplicate records and data entries entirely. This can be done through table normalization, as well as the use of appropriate indexing.
I hope this helps in some way.

MySQL: Category Tree and Products in n levels

So, let's assume I've a MySQL DB with the following tables:
Product
id
name
category_id
Category
id
name
parent_id
What's the best way to query the DB in order to get all products going down from a certain category id. For instance, if I've a tree of sub-categories where the base category id = 1 how can I get all the products under the subcategories of id =1 for an undetermined number of sub-categories.
I could do this:
SELECT * FROM `Product` WHERE category_id IN (
SELECT `id` FROM `Category` WHERE parent_id = 1
)
However it only works for the direct children of category id = 1 and not for the 2nd to n level children.
Thank you.
Edit
Some people suggested to read a blog article about this, I had a look at that article on the past also, and I made this sqlfiddle:
http://sqlfiddle.com/#!2/be72ec/1
As you can see on the query, even the simplest method they teach, to get a tree of categories doesn't output anything. What am I missing? The other methods have the same issue.
Thank you.
I looked at your sqlfiddle and came to the following conclusion.
The problem with your code is, that you are using NULL values.
Look at this sqlfiddle to see a working example: http://sqlfiddle.com/#!2/07ef7/1/0
I did some corrections on your statements and now everything works.
Here is a list with the changes i did:
Change "parent_id bigint(11) unsigned DEFAULT NULL," to "parent_id bigint(11) unsigned NOT NULL DEFAULT 0," within the create statement
Remove the foreign key constraint, but i didn't get it working with "0" as parent_id
Insert "0" instead of "NULL" as parent_id
Change data typ INT to BIGINT within the FUNCTION, because you are using this type within your creation statement
Remove the WHERE clause from the select statement
I hope that helps you!
Here are the statements, just in case sqlfiddle is not working right now:
CREATE TABLE `Category` (
`id` bigint(11) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(100) DEFAULT NULL,
`parent_id` bigint(11) unsigned NOT NULL DEFAULT 0,
PRIMARY KEY (`id`),
KEY `parent_id` (`parent_id`),
KEY `ix_hierarchy_parent` (`parent_id`, `id`)
)//
INSERT INTO `Category` (`id`, `name`, `parent_id`)
VALUES
(1,'Cat Name 1',0),
(2,'Cat Name 2',0),
(3,'Cat Name 3',2),
(4,'Cat Name 4',2),
(7,'Cat Name 5',4),
(8,'Cat Name 6',4),
(9,'Cat Name 7',4),
(10,'Cat Name 8',4),
(11,'Cat Name 9',4),
(12,'Cat Name 10',4),
(13,'Cat Name 11',2),
(16,'Cat Name 12',13),
(17,'Cat Name 13',13),
(18,'Cat Name 14',13),
(19,'Cat Name 15',13),
(20,'Cat Name 16',13),
(21,'Cat Name 17',13)//
CREATE FUNCTION hierarchy_connect_by_parent_eq_prior_id(value BIGINT) RETURNS INT
NOT DETERMINISTIC
READS SQL DATA
BEGIN
DECLARE _id BIGINT;
DECLARE _parent_id BIGINT;
DECLARE _next BIGINT;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET #id = NULL;
SET _parent_id = #id;
SET _id = -1;
IF #id IS NULL THEN
RETURN NULL;
END IF;
LOOP
SELECT MIN(id)
INTO #id
FROM `Category`
WHERE parent_id = _parent_id
AND id > _id;
IF #id IS NOT NULL OR _parent_id = #start_with THEN
SET #level = #level + 1;
RETURN #id;
END IF;
SET #level := #level - 1;
SELECT id, parent_id
INTO _id, _parent_id
FROM `Category`
WHERE id = _parent_id;
END LOOP;
END//
SELECT CONCAT(REPEAT(' ', level - 1), CAST(hi.id AS CHAR)) AS treeitem, hi.name, parent_id, level
FROM (
SELECT hierarchy_connect_by_parent_eq_prior_id(id) AS id, #level AS level
FROM (
SELECT #start_with := 0,
#id := #start_with,
#level := 0
) vars, `Category`
WHERE #id IS NOT NULL
) ho
JOIN `Category` hi
ON hi.id = ho.id

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

Select top N rows out of M groups

I have this table:
CREATE TABLE IF NOT EXISTS `catalog_sites` (
`id` int(10) unsigned NOT NULL auto_increment,
`cat_id` int(10) unsigned NOT NULL,
`date` datetime NOT NULL,
`url` varchar(255) NOT NULL,
`title` varchar(255) NOT NULL,
`description` varchar(255) NOT NULL,
`keywords` varchar(255) NOT NULL,
`visited` int(10) unsigned NOT NULL,
`shown` int(10) unsigned NOT NULL,
`meta_try` int(1) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `url` (`url`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
I think my problem is simple, but cant seem to find an appropriate solution..
So, this is a table with web-sites, I would like to get 6 sites in 6 different categories (cat_id, total: 36 rows) with the highest rating for each category. The rating is calculated as visited / shown.
I should get 36 rows containing 6 top categories (we can find them by sorting with AVG(visited / shown) ), and 6 top sites in each of these 6 categories.
If you have any ideas how this might happen differently, please tell me.
This should get you what you want using MySQL Variables, the inner query will pre-calculate the rank of visited / shown, and using an order by by the condition you want... Per Category, the highest ranks... and then using #vars will keep the #RankSeq sequentially 1-? per category. From that Prequery (aliased PQ), the OUTER query just queries the PreQuery where the URL's Rank Sequence is <= 6
To further ensure you are only getting the top 6 categories, the inner PreQuery also has a pre-query / limit for the "TopCategories" (alias)
select
PQ.URL,
PQ.Cat_ID,
PQ.Rank,
PQ.URLRankSeq
from
( select
CS.cat_id,
(CS.visited / CS.shown ) as Rank,
CS.url,
#RankSeq := if( #LastCat = CS.Cat_ID, #RankSeq +1, 1 ) URLRankSeq,
#LastCat := CS.Cat_ID as ignoreIt
from
( select cat_id,
avg( visited / shown )
from catalog_sites
group by 1
order by 2 desc
limit 6 ) TopCategories
JOIN catalog_sites CS
on TopCategories.Cat_ID = CS.Cat_ID,
(select #RankSeq := 0, #LastCat = 0 ) SQLVars
order by
CS.cat_id,
Rank ) PQ
where
PQ.URLRankSeq <= 6
I've tried your example, but it doesn't really work for me, or I just don't know how to adapt it to my case. Anyway, I'm still a noob as far as SQL goes, so I couldn't understand your query.
I have managed to solve my problem however. It's complicated and probably the worst possible approach. It is slow too, but I'll cache the results, so that shouldn't be a problem.
Here is my solution:
SET #site_limit = 2;
SET #cat_limit = 6;
SET #row = 0;
SET #limiter = 0;
SET #last_cat = 0;
SELECT `cat_id`, `url`, `visited` / `shown` AS `rating`, #limiter := IF(#last_cat = `cat_id`, IF(#limiter >= #site_limit - 1, #limiter, #limiter + 1), 0) AS `limiter`, #last_cat := `cat_id` AS `last_cat`
FROM `catalog_sites`
WHERE `cat_id`
IN (
SELECT `cat_id`
FROM (
SELECT `cat_id`, #row := #row + 1 AS `row`
FROM (
SELECT `cat_id`
FROM `catalog_sites`
GROUP BY `cat_id`
ORDER BY AVG(`visited` / `shown`) DESC
) AS derived1
) AS derived2
WHERE `row` <= #cat_limit
)
GROUP BY `cat_id`, `limiter`
ORDER BY `cat_id`, `rating` DESC