Multiple unique entries on table update mysql - mysql

Right now I have a table with an auto increment id number, a name, and a definition
I am updating the table with values from another table using
INSERT INTO words(id, word, definition) SELECT id, word, definition FROM temp
ON DUPLICATE KEY UPDATE words.word = temp.word, words.definition=temp.definition;
The table temp has the same exact column layout as the table I am using, and it works fine except when I delete an entry from the middle of temp and then update my main table.
For example,
temp
id word definition
1 bob is a cat
2 sam is a dog
3 doug is a monk
4 croe is a bird
table main is set to that
Then I remove row 2 from temp
temp
id word definition
1 bob is a cat
2 doug is a monk
3 croe is a bird
and then update main table
main
id word definition
1 bob is a cat
2 sam is a dog
3 croe is a bird
4 croe is a bird
because temp only has 3 rows now, but main HAD 4, the 4th row isn't deleted. I tried to fix this by making word a unique column, and now I get the error that there is a duplicate entry for key 'word'.
So how do I fix this?

From the MySQL manual,
In general, you should try to avoid using an ON DUPLICATE KEY UPDATE
clause on tables with multiple unique indexes.
so, what you could do is make word your primary key, and get rid of the id column. That should do the trick :)
Your query then becomes
INSERT INTO words(word, definition) SELECT word, definition FROM temp
ON DUPLICATE KEY UPDATE words.word = temp.word, words.definition=temp.definition;
If you need arbitrary sorting, I would create an additional table
CREATE TABLE word_order (VARCHAR(30) PRIMARY KEY, sort_order INT)
and then when you run your queries
SELECT words.word,
words.definition
FROM words
JOIN word_order
ON words.word = word_order.word
ORDER BY word_order.sort_order
Your INSERTS become a little more complicated though, you'd have to run multiple inserts. See sql - insert into multiple tables in one query.
Also, this CodeProject article has some more ideas on the topic.

Related

mariaDB insert multiple rows where 2 cols not exists

I realize similar questions have been asked before, but I can't seem to find a solution that fits this particular scenario.
I would like to insert multiple rows of data into a mariaDB table where the data must be unique (primary key excluded).
Sample table:
enrollmentsID
classID
userID
1
1
2
2
1
3
3
1
4
4
2
2
5
2
7
So if I want to insert a number of rows, I don't want to duplicate what's already present.
The general idea is something like:
INSERT INTO `enrollments` (`enrollmentsID`, `classID`, `userID`)
VALUES (NULL,1,2),(NULL,1,3),(NULL,1,4),(NULL,1,5)
WHERE NOT EXISTS (
SELECT `enrollments`.`classID`, `enrollments`.`userID`
FROM `enrollments`)
Here, userID 5 would insert but userID 3 and userID 4 would be ignored.
Unfortunately, the WHERE is causing issues... Thanks for any help provided.
As P.Salmon mentioned in the comments, a UNIQUE index on the two columns is likely what you need. The index needs to be on both columns, not a UNIQUE index for each column.
ALTER TABLE enrollments
ADD UNIQUE INDEX (`classID`,`userID`)
From there you can do INSERT INGORE INTO instead of INSERT INTO and that will only insert the unique entries.

How to insert into table a new row then do nothing if already exists(without UNIQUE key)

Let's say I have these two tables. Where I insert employees to employee table coming from the staging table.
staging table:
id
employee_id
name
1
12
Paul
2
13
Kyle
employee table
id
employee_id
name
5
4
Will
6
13
Kyle
Now, on the employee table let's say I'd like to copy what's on my staging table currently, using the INSERT SELECT INTO statement, Paul will be inserted but I don't want Kyle to be inserted since he's on the employee table already(employee.employee_id is the defining column).
I know this could be done by just setting a unique or primary key, on employee_id and just using the statement ON DUPLICATE KEY UPDATE then do nothing by just setting them back to their original values.
I'm new to SQL, and I'm stuck with the solution setting a UNIQUE key and ON DUPLICATE KEY UPDATE statement, but I'd like to know how to do this without that solution I mentioned?
First of all, you should keep in mind that the decision whether to create unique or primary keys or not does not depend on how to create insert statements or such. It's a matter of what your table should do and what not.
In order to achieve your goal, you can add a where to your insert statement which excludes the already existing entries, as example:
INSERT INTO employees (id, employee_id, name)
SELECT id, employee_id, name
FROM staging
WHERE employee_id NOT IN (SELECT employee_id FROM employees)
Break the problem down into its constituent parts
get a list of employees who are in the staging table but not in the target table
insert those records only
Part 1 can be achieved with a Left Join and Where condition that the target table is null. Wrap that up as a CTE and then use it in 2)

Remove duplicate values without ID

I have a table like this:
uuid | username | first_seen | last_seen | score
Before, the table used the primary key of a "player_id" column that ascended. I removed this player_id as I no longer needed it. I want to make the 'uuid' the primary key, but there's a lot of duplicates. I want to remove all these duplicates from the table, but keep the first one (based off the row number, the first row stays).
How can I do this? I've searched up everywhere, but they all show how to do it if you have a row ID column...
I highly advocate having auto-incremented integer primary keys. So, I would encourage you to go back. These are useful for several reasons, such as:
They tell you the insert order of rows.
They are more efficient for primary keys.
Because primary keys are clustered in MySQL, they always go at the end.
But, you don't have to follow that advice. My recommendation would be to insert the data into a new table and reload into your desired table:
create temporary table tt as
select t.*
from tt
group by tt.uuid;
truncate table t;
alter table t add constraint pk_uuid primary key (uuid);
insert into t
select * from tt;
Note: I am using a (mis)feature of MySQL that allows you to group by one column while pulling columns not in the group by. I don't like this extension, but you do not specify how to choose the particular row you want. This will give values for the other columns from matching rows. There are other ways to get one row per uuid.

How to delete a certain row from mysql table with same column values?

I have a problem with my queries in MySQL. My table has 4 columns and it looks something like this:
id_users id_product quantity date
1 2 1 2013
1 2 1 2013
2 2 1 2013
1 3 1 2013
id_users and id_product are foreign keys from different tables.
What I want is to delete just one row:
1 2 1 2013
Which appears twice, so I just want to delete it.
I've tried this query:
delete from orders where id_users = 1 and id_product = 2
But it will delete both of them (since they are duplicated). Any hints on solving this problem?
Add a limit to the delete query
delete from orders
where id_users = 1 and id_product = 2
limit 1
All tables should have a primary key (consisting of a single or multiple columns), duplicate rows doesn't make sense in a relational database. You can limit the number of delete rows using LIMIT though:
DELETE FROM orders WHERE id_users = 1 AND id_product = 2 LIMIT 1
But that just solves your current issue, you should definitely work on the bigger issue by defining primary keys.
You need to specify the number of rows which should be deleted. In your case (and I assume that you only want to keep one) this can be done like this:
DELETE FROM your_table WHERE id_users=1 AND id_product=2
LIMIT (SELECT COUNT(*)-1 FROM your_table WHERE id_users=1 AND id_product=2)
Best way to design table is add one temporary row as auto increment and keep as primary key. So we can avoid such above issues.
There are already answers for Deleting row by LIMIT. Ideally you should have primary key in your table. But if there is not.
I will give other ways:
By creating Unique index
I see id_users and id_product should be unique in your example.
ALTER IGNORE TABLE orders ADD UNIQUE INDEX unique_columns_index (id_users, id_product)
These will delete duplicate rows with same data.
But if you still get an error, even if you use IGNORE clause, try this:
ALTER TABLE orders ENGINE MyISAM;
ALTER IGNORE TABLE orders ADD UNIQUE INDEX unique_columns_index (id_users, id_product)
ALTER TABLE orders ENGINE InnoDB;
By creating table again
If there are multiple rows who have duplicate values, then you can also recreate table
RENAME TABLE `orders` TO `orders2`;
CREATE TABLE `orders`
SELECT * FROM `orders2` GROUP BY id_users, id_product;
You must add an id that auto-increment for each row, after that you can delet the row by its id.
so your table will have an unique id for each row and the id_user, id_product ecc...

How Do I delete these orphan records from my Table, Iteratively?

I have 2 tables like this
words(word_id, value);
word_map(sno(auto_inc), wm_id, service_id, word_id, base_id, root_id);
in which sno is auto incremented just for indexing.
wm_id is the actual id which are unique for each service like
(serviceid, wm_id together form a unique key).
base_id and root_id are referenced to wm_id i.e., I store the values of respective wm_id of new word being inserted.
My Requirement now is I want to delete the records from this table where, a words's base_id or root_id does not exists in the table
For example,
A new word with tr_id = 4, its base_id = 2 and root_id = 1 then There must two other records with tr_id s 2 and 1 if not we can call it as an orphan and that record with wm_id = 4 must be deleted, then records with other wm_ids having this 4 as base_id or root_id must also be deleted as they r also now orphans if 4 gets deleted and so on.
Can anybody suggest me the solution for the problem.
What I tried:
I tried write a procedure using while in which it has a query like,
delete from words_map where base_id not in (select wm_id from words_map) or root_id not in (select wm_id from words_map)
But deleting/ or updating on same table using this kind of nested queries is not possible, So I am searching for an alternate way.
What I doubt is :
I thought of reading these wm_ids into an array then reading one by one deleting based on that, but I dont think we have arrays in stored
procedures.
Is Cursor an alternative for this sitution.
or any other best solution for this problem.
EDIT 1: Please go through this http://sqlfiddle.com/#!2/a4b6f/15 for clear experimental data
Any and early help would be appreciated