How do i make duplicates in a existing column unique? - mysql

I am using MySQL 5.6 Server. I use Navicat to work in the DB.
I have searched and found alot of possible solutions to my problem but none of them have worked for me.
I have a table with around 36000 rows. I have a column wich allowes duplicate entrys but i would like to make the duplicates in the row unique. Column with duplicates
I can find my duplicates using this query.
But there is to many to manually edit them all. Search Result
SELECT name, COUNT(ItemTemplate_ID)
FROM itemtemplate
GROUP BY ItemTemplate_ID
HAVING ( COUNT(ItemTemplate_ID) > 1 )
What i am looking for is a way to do one of these things.
Update the duplicates with new unique entries.
Add a text entry in another column for every duplicates. (I have a couple of empty columns i can use to add some text too.
Update the entire column with unique entries. ( Doesnt matter what its calle just has to be unique.)
Thanks in advance.
Edit - There allready is a unique column called Id_nb.
The column i want to change entries in should not be unique.

Let me assume that you do not have a unique column in the table. If so, you can do this with variables:
set #rn := 0;
set #it := '';
update itemtemplate it
set it.ItemTemplate_ID = (case when #it = it.ItemTemplate_ID
then concat_ws('_', it.name, (#rn := #rn + 1))
when #it := it.ItemTemplate_ID
then if(#rn := 0, it.ItemTemplate_ID, it.ItemTemplate_ID)
else if(#rn := 0, it.ItemTemplate_ID, it.ItemTemplate_ID)
end)
order by it.ItemTemplate_ID;
This method does assume that there are not already columns with names like "ABC" and "ABC_1".

Update the duplicates with new unique entries.
Let's assume that you have a unique column named id.
update itemtemplate set ItemTemplate_ID = (select md5(uuid())) where
FIND_IN_SET(id,(SELECT GROUP_CONCAT(id) FROM itemtemplate GROUP BY ItemTemplate_ID HAVING ( COUNT(ItemTemplate_ID) > 1 ) ));
Add a text entry in another column for every duplicates. (I have a couple of empty columns i can use to add some text too.
update itemtemplate set ItemTemplate_ID = (select md5(uuid())), emptyColumn='text' where
FIND_IN_SET(id,(SELECT GROUP_CONCAT(id) FROM itemtemplate GROUP BY ItemTemplate_ID HAVING ( COUNT(ItemTemplate_ID) > 1 ) ));
Sorry, I don't quite understand the third question.
By the way,if you have executed the first sql, the second sql will not work anymore.

Related

MySQL user variable addition: '+1' return '+2'

I'm coding a movie search engine called Movieovo, I want to select the top 5 rows (movie links) from each group (movie title), but I met a problem in this SQL query:
SELECT link_movie_id, link_id,
#num := if(#link_movie_id = link_movie_id, #num + 1, 1) as row_number,
#link_movie_id := link_movie_id as dummy
FROM link GROUP BY link_movie_id, link_id HAVING row_number <= 5 LIMIT 30
Result: ( Too many characters so I upload as an image )
http://i.imgur.com/phFzUF1.png
You can see "row_number" does not +1 each time
I tried directly in MySQL command line shows me the same results, can anyone help me? I have already wasted 5 hours in this problem..
You are incrementing link_movie_id by 1, but you are grouping by link_movie_id and link_id. With the effect, for some link_movie_id, there are multiple values of link_id in the result. If you are want to get what you are looking for, either group by a single field, or increment it based on a concatenated combination of link_movie_id and link_id.

MySQL insert rows using from select statment while incrementing a a user definable order

What I am doing here is turning a quote into a PO, this is just one the queries I'm using to do this. The primary key of router is RN, a unique key in this table is Line Order. I'm using Line Order to allow the user to define the order of the rows in router. Since RN is set to auto_increment I don't have to worry about that. The problem is Line Order
on the router. I select multiple rows from rfq_operations for inserting into router, but it gives all the rows the same Line Order value, I need them to increment 1 from MAX(router.Line Order)
INSERT INTO `router`(`Work Order`, `Line Order`, `Estimated Time`,`Estimated Time Unit`, `Work Center`, `Work Description`, `Work Instruction`)
SELECT ?,(SELECT 1+IFNULL(MAX(`Line Order`),1) FROM `router`),CEIL(((`rfq_operations`.`Program Time`+`rfq_operations`.`Setup Time`+(`rfq_operations`.`Run Time`*(?/`rfq_operations`.`Conversion`)))/60))
,'Hours',`rfq_operations`.`Work Center`,`workcenter`.`Information`,`rfq_operations`.`Instructions`
FROM `rfq_operations`
LEFT JOIN `workcenter`
ON `rfq_operations`.`Work Center`=`workcenter`.`RN`
WHERE `rfq_operations`.`RFQ Line`=?
ORDER BY `rfq_operations`.`Line Order`
The select query is run then the results are inserted into the final table. So, you only get one value. You don't see changes to the table during the select.
In any case, you can do what you want with variables. Your query is a bit complicated, but here is the idea:
insert into router(col1, . . .)
select (#rn := #rn + 1), . . .
from . . . cross join
(select #rn := coalesce(max(`Line Order`), 0) from router) vars;
This initializes the #rn variable to the maximum value. It then increments it for each row in the subquery.
That said, the proper thing to do is to have an auto-incrementing key for this. Just define Line Order as an auto-incrementing primary key and the database will increment values for you.

MySQL batch queries with limit

I need to change the ownership of several possessions in my MySQL table. The thing that's tripping me up is that there are several identical goods and I don't want to change all of them.
Right now, I'm doing it with queries like this:
UPDATE possessions SET citizen_id=1 WHERE citizen_id=2 AND good_id=8 LIMIT 1
UPDATE possessions SET citizen_id=2 WHERE citizen_id=4 AND good_id=2 LIMIT 1
UPDATE possessions SET citizen_id=4 WHERE citizen_id=3 AND good_id=5 LIMIT 2
There are, some times, a lot of these and they're all so similar that I feel like there should be a way to submit them in a batch. The examples I can find that show batch updates don't allow setting individual limits on each update like I need to.
Do you know of any way I can make this process faster?
The following method relies on the fact that the possessions table has a primary key and citizen_id is not part of it. Here's the idea:
Put all the parameters of the update (citizen_id and good_id to filter on, the new values of citizen_id and the numbers of rows to update) into some storage, a dedicated table, perhaps, or a temporary table.
Assign row numbers to possessions rows partitioning on (citizen_id, good_id), then join the ranked row set to the parameter table to filter the original full set on citizen_id and good_id, as well as the number of rows.
Join possessions and the result of the previous join on the primary key values and update citizen_id with the new values.
In MySQL's SQL, the above might look like this:
UPDATE possessions AS p
INNER JOIN
(
SELECT
#r := #r * (#c = p.citizen_id AND #g = p.good_id) + 1 AS r,
p.possession_id,
#c := p.citizen_id AS citizen_id,
#g := p.good_id AS good_id
FROM
possessions AS p
CROSS JOIN
(SELECT #r := 0, #c := 0, #g := 0) AS x
ORDER BY
p.citizen_id,
p.good_id
) AS f ON p.possession_id = f.possession_id
INNER JOIN
possession_updates AS u ON u.citizen_id = f.citizen_id AND u.good_id = f.good_id
SET
p.citizen_id = u.new_citizen_id
WHERE
f.r <= u.row_count
;
The possessions_update is the table containing the parameter values.
The query uses a known method of row numbering that employs variables, which is implemented in the f subquery.
I don't have MySQL so I can't test this properly from the performance point of view, but at least you can see from this SQL Fiddle demo that the method works. (The UPDATE statement is in the schema script, because SQL Fiddle doesn't allow data modification statements in the right-side script for MySQL. The right side just returns the post-UPDATE contents of possessions.)

Reorder a MYSQL table

I have a MySql table with a 'Order' field but when a record gets deleted a gap appears
how can i update my 'Order' field sequentially ?
If possible in one query 1 1
id.........order
1...........1
5...........2
4...........4
3...........6
5...........8
to
id.........order
1...........1
5...........2
4...........3
3...........4
5...........5
I could do this record by record
Getting a SELECT orderd by Order and row by row changing the Order field
but to be honest i don't like it.
thanks
Extra info :
I also would like to change it this way :
id.........order
1...........1
5...........2
4...........3
3...........3.5
5...........4
to
id.........order
1...........1
5...........2
4...........3
3...........4
5...........5
In MySQL you can do this:
update t join
(select t.*, (#rn := #rn + 1) as rn
from t cross join
(select #rn := 0) const
order by t.`order`
) torder
on t.id = torder.id
set `order` = torder.rn;
In most databases, you can also do this with a correlated subquery. But this might be a problem in MySQL because it doesn't allow the table being updated as a subquery:
update t
set `order` = (select count(*)
from t t2
where t2.`order` < t.`order` or
(t2.`order` = t.`order` and t2.id <= t.id)
);
There is no need to re-number or re-order. The table just gives you all your data. If you need it presented a certain way, that is the job of a query.
You don't even need to change the order value in the query either, just do:
SELECT * FROM MyTable WHERE mycolumn = 'MyCondition' ORDER BY order;
The above answer is excellent but it took me a while to grok it so I offer a slight rewrite which I hope brings clarity to others faster:
update
originalTable
join (select originalTable.ID,
(#newValue := #newValue + 10) as newValue
from originalTable
cross join (select #newValue := 0) newTable
order by originalTable.Sequence)
originalTable_reordered
on originalTable.ID = originalTable_reordered.ID
set originalTable.Sequence = originalTable_reordered.newValue;
Note that originalTable.* is NOT required - only the field used for the final join.
My example assumes the field to be updated is called Sequence (perhaps clearer in intent than order but mainly sidesteps the reserved keyword issue)
What took me a while to get was that "const" in the original answer was not a MySQL keyword. (I'm never a fan of abbreviations for that reason -- the can be interpreted many ways at times especially at these very when it is best they not be misinterpreted. Makes for verbose code I know but clarity always trumps convenience in my books.)
Not quite sure what the select #newValue := 0 is for but I think this is a side effect of having to express a variable before it can be used later on.
The value of this update is of course an atomic update to all the rows in question rather than doing a data pull and updating single rows one by one pragmatically.
My next question, which should not be difficult to ascertain, but I've learned that SQL can be a trick beast at the best of times, is to see if this can be safely done on a subset of data. (Where some originalTable.parentID is a set value).

MySQL Update a column value with the rowid of the group

I have a table of images, which are associated with a particular group (vehID) and I need to create their order for each group.
This is for an initial image entries position for a field I forgot to design in.
I have been playing with #row, but not getting very far.
set #row= 0;
select #row:=#row+1 as row, vehID,imgID from images group by vehID;
This gives me the rowID but does not reset for each group
Each vehID has 1 to n entries and I wish to calculate that value and update that rows' entry with the calculated value.
I can not work out how to reset #row to 0 on a change of vehID. Probably some sub-select.
If I can get Select to work any advice on how code the UPDATE if not obvious would be appreciated
Update images set imgPosition = Calculated Value where imgID = current imgID
you just need to declare another variable that holds the previous vehID. then using an IF statement you can compare the vehID with the previous one and set the row number accordingly. and then you set the previous vehID variable to be the vehID of the current row.
please note that I changed "group by" to "order by". this is for two reasons:
1- to list all rows
2- to make sure that rows from same id are following each other. otherwise comparing with previous value will not be correct.
and last, make sure you compare the previous vehID value and decide what the rownum is before you reset the previous variable to hold the value of the current line.
set #previous_vehID= 0;
set #row= 0;
select if(#previous_vehID=vehID, #row:=#row+1, #row:=1) as row,#previous_vehID:=vehID, vehID,imgID from images order by vehID
EDIT:
I just missed the update part. you can try cross table update for that:
set #previous_vehID= 0;
set #row= 0;
update images a, (
select if(#previous_vehID=vehID, #row:=#row+1, #row:=1) as row,#previous_vehID:=vehID, vehID,imgID from images order by vehID ) aa
set a.imgPosition = aa.row where a.vehID=aa.vehID and a.imgID=aa.imgID
the above makes the select and the update in a single statement/query. if not working, insert the results into a temporary table and use them to make an update in a separate statement.