MySql update with different values a column for duplicate columns - mysql

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.

Related

How to select the latest record of each different value of a column

Based on this table:
How can I return the latest record of each different vehicle ( assuming I know the values, but if there is a solution that assumes I don't know them it would be better) so let's say for this particular database it would return those in the red box (column id is A.I.):
i have tried with MAX (id) but for some reason it returns null
Any ideas?
You can select max id from the different value that you are asking. This example works if your id is auto increment and the latest the id inserted the bigger the date.
For example:
create table `car` (
id int(9) not null auto_increment,
`date` varchar(40) default null,
staff varchar(50) default null,
staffindex int(3) default null,
vehicle varchar(50) default null,
vehicleindex int(3) default null,
fuel varchar(30) default null,
km varchar(30) default null,
comments varchar(255) default null,
Primary key id(`id`) );
insert into car values (1,"26/08/2021","Christos","0","ITY-2683","2","50","128.315",""), (2,"27/08/2021","Sotiris","1","IOY-3949","3","65","322.522","car needs cleaning"), (3,"26/08/2021","Vaggelis","0","ITY-2682","2","50","128.315",""),(4,"26/08/2021","Teo","1","YTI-7963","3","65","322.522","car needs cleaning"),(5,"26/08/2021","Christos","0","ITY-2683","2","50","128.315",""), (6,"27/08/2021","Sotiris","1","IOY-3949","3","65","322.522","car needs cleaning"), (7,"26/08/2021","Vaggelis","0","ITY-2682","2","50","128.315",""),(8,"26/08/2021","Teo","1","YTI-7963","3","65","322.522","car needs cleaning");
select * from car;
And for your solution you can use:
select * from car where id in (select max(id) from car group by staff) order by id desc;
I am using MariaDB, the same is for MySQL
You can try something like this.
Select Max(Dates) MaxDate, vehicle From Table1 Group by vehicle
From the above query you will get maxDate for each vehicle, if this is
not your answer then please provide more information what and how you
want to display your records.
Selecting the max date might help you to solve your problem.
SELECT * FROM table
WHERE Dates IN (SELECT max(Dates) FROM table);
How can I return the latest record of each different vehicle
One method is a correlated subquery. Assuming by latest you mean by date:
select t.*
from t
where t.date = (select max(t2.date) from t t2 where t2.vehicle = t.vehicle);
With an index on (vehicle, date), this is probably the most performant solution.
MySQL also lets you use in with tuples:
select t.*
from t
where (t.vehicle, t.date) in (select t2.vehicle, max(t2.date)
from t t2
group by t2.vehicle
);

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

SQL Key value table--select ids that have multiple keys

I need to obtain records in a key-value table with the following structure:
CREATE TABLE `PROPERTY` (
`id` int(11) NOT NULL,
`key` varchar(64) NOT NULL,
`value` text NOT NULL,
PRIMARY KEY (`id`,`key`)
);
I need to get all ids that have MULTIPLE specific key-value entries. For example, all ids that have keys "foo", "bar", and "foobar".
Simply use GROUP BY to group and then check the group count to count multiple values:
Select
id
from
`PROPERTY`
group by
key, value
having
count(*) > 1
Given updated question...
since you know the specific keys, you also know how many there are... so a count distinct in having should do it... along with a where...
SELECT id
FROM `PROPERTY`
Where key in ('foo','bar','foobar')
GROUP BY ID
having count(distinct key) = 3
I f you need the id of all the rows for key,value count(= >1)
select id from `PROPERTY`
where (key, value) in (select key, value from `PROPERTY`group by
key, value
having
count(*) > 1)

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.

Insert and set value with max()+1 problems

I am trying to insert a new row and set the customer_id with max()+1. The reason for this is the table already has a auto_increatment on another column named id and the table will have multiple rows with the same customer_id.
With this:
INSERT INTO customers
( customer_id, firstname, surname )
VALUES
((SELECT MAX( customer_id ) FROM customers) +1, 'jim', 'sock')
...I keep getting the following error:
#1093 - You can't specify target table 'customers' for update in FROM clause
Also how would I stop 2 different customers being added at the same time and not having the same customer_id?
You can use the INSERT ... SELECT statement to get the MAX()+1 value and insert at the same time:
INSERT INTO
customers( customer_id, firstname, surname )
SELECT MAX( customer_id ) + 1, 'jim', 'sock' FROM customers;
Note: You need to drop the VALUES from your INSERT and make sure the SELECT selected fields match the INSERT declared fields.
Correct, you can not modify and select from the same table in the same query. You would have to perform the above in two separate queries.
The best way is to use a transaction but if your not using innodb tables then next best is locking the tables and then performing your queries. So:
Lock tables customers write;
$max = SELECT MAX( customer_id ) FROM customers;
Grab the max id and then perform the insert
INSERT INTO customers( customer_id, firstname, surname )
VALUES ($max+1 , 'jim', 'sock')
unlock tables;
Use alias name for the inner query like this
INSERT INTO customers
( customer_id, firstname, surname )
VALUES
((SELECT MAX( customer_id )+1 FROM customers cust), 'sharath', 'rock')
SELECT MAX(col) +1 is not safe -- it does not ensure that you aren't inserting more than one customer with the same customer_id value, regardless if selecting from the same table or any others. The proper way to ensure a unique integer value is assigned on insertion into your table in MySQL is to use AUTO_INCREMENT. The ANSI standard is to use sequences, but MySQL doesn't support them. An AUTO_INCREMENT column can only be defined in the CREATE TABLE statement:
CREATE TABLE `customers` (
`customer_id` int(11) NOT NULL AUTO_INCREMENT,
`firstname` varchar(45) DEFAULT NULL,
`surname` varchar(45) DEFAULT NULL,
PRIMARY KEY (`customer_id`)
)
That said, this worked fine for me on 5.1.49:
CREATE TABLE `customers` (
`customer_id` int(11) NOT NULL DEFAULT '0',
`firstname` varchar(45) DEFAULT NULL,
`surname` varchar(45) DEFAULT NULL,
PRIMARY KEY (`customer_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1$$
INSERT INTO customers VALUES (1, 'a', 'b');
INSERT INTO customers
SELECT MAX(customer_id) + 1, 'jim', 'sock'
FROM CUSTOMERS;
insert into table1(id1) select (max(id1)+1) from table1;
Use table alias in subquery:
INSERT INTO customers
( customer_id, firstname, surname )
VALUES
((SELECT MAX( customer_id ) FROM customers C) +1, 'jim', 'sock')
None of the about answers works for my case. I got the answer from here, and my SQL is:
INSERT INTO product (id, catalog_id, status_id, name, measure_unit_id, description, create_time)
VALUES (
(SELECT id FROM (SELECT COALESCE(MAX(id),0)+1 AS id FROM product) AS temp),
(SELECT id FROM product_catalog WHERE name="AppSys1"),
(SELECT id FROM product_status WHERE name ="active"),
"prod_name_x",
(SELECT id FROM measure_unit WHERE name ="unit"),
"prod_description_y",
UNIX_TIMESTAMP(NOW())
)
Your sub-query is just incomplete, that's all. See the query below with my additions:
INSERT INTO customers ( customer_id, firstname, surname )
VALUES ((SELECT MAX( customer_id ) FROM customers) +1), 'jim', 'sock')
You can't do it in a single query, but you could do it within a transaction. Do the initial MAX() select and lock the table, then do the insert. The transaction ensures that nothing will interrupt the two queries, and the lock ensures that nothing else can try doing the same thing elsewhere at the same time.
We declare a variable 'a'
SET **#a** = (SELECT MAX( customer_id ) FROM customers) +1;
INSERT INTO customers
( customer_id, firstname, surname )
VALUES
(**#a**, 'jim', 'sock')
This is select come insert sequel.
I am trying to get serial_no maximum +1 value and its giving correct value.
SELECT MAX(serial_no)+1 into #var FROM sample.kettle;
Insert into kettle(serial_no,name,age,salary) values (#var,'aaa',23,2000);