Im curious if there is a way to insert into MySQL and avoid duplicates. I know there are three primary ways of accomplishing it. Either Replace, insert ignore or insert on duplicate key. I believe that each of these rely on a unique primary key which for me is a auto increment id field. This id field does not have any value for my particular inserting needs instead i want to check if a few fields contain the same value if not dont insure
ex:
INSERT INTO table (name, team, email) VALUES (:n, :t, :e)
if i had three data sets like so
1) array (":n" => "john doe", ":t" => 1, ":e" => john#doe.com);
2) array (":n" => "Jane doe", ":t" => 1, ":e" => john#doe.com);
3) array (":n" => "john doe", ":t" => 1, ":e" => john1#doe.com);
4) array (":n" => "john doe", ":t" => 2, ":e" => john1#doe.com);
Assuming there are no values in the table
1, 3 and 4 would be inserted but 2 would not as the team and email are not unique
I am aware i could create a fourth column and add the email and team to it and create a unique value and use this however i would prefer not to do so as it is redundant data .
Thanks
You can create an UNIQUE constrain
ALTER TABLE `tableName` ADD UNIQUE `unique_idx`(`name`, `team`, `email`);
If the id field has no value for you, don't bother with it. The desired behavior you're describing is that of a composite key, so make a composite key.
First, scrap the one that exists and is of no value...
ALTER TABLE YourTableName DROP PRIMARY KEY;
Then create the new composite one...
ALTER TABLE YourTableName ADD PRIMARY KEY (name, team, email);
You can try using DUAL
INSERT INTO table (name, team, email)
SELECT :n, :t, :e
FROM DUAL
WHERE :t NOT IN (SELECT team FROM table WHERE email = :e)
Related
My columns are like this. column "a" is primary and auto incremantal.
a | b | x | y
When inserting new data, i need to check x and y columns shouldn't be exist together.
To clarify, imagine this row is at database with these values
(2, "example.com" , "admin", "123456")
I should able to insert both of these columns
(3, "example.com" , "user", "123456")
(4, "example2.com" , "admin", "123456")
But i shouldn't able to insert this column
(5, "example.com" , "admin", "5555555")
Because "example.com" and "admin" values already in database on a row. It doesn't matter column "y" is same or not.
How can i do this?
Create a composite unique index. This will allow any number of duplicates in the individual fields, but the combination needs to be unique.
CREATE UNIQUE INDEX ix_uq ON tablename (b, x);
...and use INSERT IGNORE to insert if the unique index is not violated. If it is, just ignore the insert.
INSERT IGNORE INTO test (a,b,x,y) VALUES (5, "example.com" , "admin", "5555555");
If you want to insert unless there's a duplicate, and update if there is, you can also use INSERT INTO ... ON DUPLICATE KEY UPDATE;
Ref: MySQL only insert new row if combination of columns (which allow duplicates) is unique
You want to let the database do the work. Although you can set up a condition within a query, that condition may not be universally true or someone might use another query.
The database can check this with a unique constraint or index. Actually, the unique constraint is implementing using a unique index:
create unique index unq_t_b_x on t(b, x);
(The columns can be in either order.)
The insert would then look like:
insert into t(b, x, y)
values ('example.com', 'admin', '5555555')
on duplicate key update b = values(b);
Note that the auto-incremented value is not included in the update.
The on duplicate key update just prevents the insert from generating an error. It is better than insert ignore because the latter will ignore all errors, and you just want to ignore the one caused by the duplicate key.
I have two tables, one of them is 'user_flag' and the other is 'playlist_data'.
I want to take all 'object_id' column entries of 'user_flag' and place them into the respective 'object_id' column of 'playlist_data', but only if those entries have '3' as the 'user' entry, and that they do not already exist (no duplicate 'object_id's!).
I tried to learn how to do it and this is what I found:
INSERT INTO playlist_data (object_id)
SELECT object_id FROM user_flag
WHERE user='3';
ON DUPLICATE KEY UPDATE object_id=object_id
Will this work properly?
But I'm also trying to do more at the same time, and I can't seem to find an answer:
1) I want to also insert new data with this. I want all of the newly inserted entries to also contain '5' in the 'filetype' column of 'playlist_data'.
Do I just
INSERT INTO playlist_data (filtype)
VALUES (5)
in the middle of all of this?
2) Both tables also have an 'id' column, will it automatically generate a new id followed from the latest 'id' of 'playlist_data'?
As in for example, I'm transferring from 'user_flag' an entry with the 'id' of '150', while the highest 'id' in 'playlist_data' is '63', will the inserted one by '64', or do I need to define that somehow?
Just add the value in the SELECT:
INSERT INTO playlist_data (object_id, filtype)
SELECT object_id, 5
FROM user_flag
WHERE user = 3
ON DUPLICATE KEY UPDATE object_id = VALUES(object_id);
Notes:
I am guessing that the id columns are numbers. Hence, I removed the single quotes.
I use VALUES(object_id) in the ON DUPLICATE KEY UPDATE.
It is important to have the semicolon only at the very end of the statement.
Hi I've been trying to get this to work, I thought I had it with mysql - INSERT... ON DUPLICATE KEY UPDATE, but no luck.
I have a table as such:
sessionID is unique,
productID references another table and is not unique, but not common, should be a max of 3 rows containing the same value,
sessionType is either 1, 2 or 3, and would link with productID,
I need to check if the table has a row where there is a matching pair of productID and sessionType, if there is then sessionDate & sessionCapacity in that row should be UPDATED, if there isn't then a new row inserted.
$vals = array($pID,$data['pSessionDate'],'1',$data['pQty'],$pID,$data['pSessionDate'],'1',$data['pQty']);
$db->Execute("INSERT INTO VividStoreSessions (pID,sDate,sType,sCapacity) VALUES (?,?,?,?) ON DUPLICATE KEY UPDATE pID=?,sDate=?,sType=?,sCapacity=?",$vals);
Hope that makes sense to someone and thanks in advance for any help!
Your insert looks valid. But, first you need a unique index/constraint:
create unique index unq_VividStoreSessions_productId_sessionType
on VividStoreSessions, productId, sessionType)
Then you can write the code to only use four parameters:
INSERT INTO VividStoreSessions (pID, sDate, sType, sCapacity)
VALUES (? ,?, ?, ?)
ON DUPLICATE KEY UPDATE sDate = VALUES(sDate), Capacity = VALUES(Capacity);
Finally, you need to ensure that sType only takes on the values of 1, 2, or 3. Perhaps you want to enforce this at the application layer. Otherwise, you need a trigger or foreign key constraint to ensure that there are only three rows.
So I have a 'recently_viewed' table with columns
product|user|time
However, if a user views a product they have already viewed, it will create a new row. What is the most efficient way of covering this possibility (while keeping the possibility that it is the first time they viewed it)? overwriting the old TIME they viewed it or deleting the old table row (and simultaneously creating the new row)? I can think of some inefficient ways to do it (querying first to see if it's in the table, but this requires multiple statements), but I suspect there is something far more efficient.
INSERT INTO recently_viewed ...
Sincere thanks for any help. It is greatly appreciated from an amateur.
You can check whether record for user exists in recently_viewed,
IF EXISTS (SELECT * FROM recently_viewed WHERE user = "user_id")
BEGIN
#UPDATE query
END
ELSE
BEGIN
#INSERT query
END
You can use define (product, user) as UNIQUE, for example you can set it as the PRIMARY KEY of your table:
CREATE TABLE tablename (
product INT,
user INT,
time DATETIME,
PRIMARY KEY (product, user)
);
(or you can also create a UNIQUE index) and then use an INSERT INTO ... ON DUPLICATE query:
INSERT INTO tablename (product, user, `time`)
VALUES (1, 1, '2015-01-01 10:00:00'),
ON DUPLICATE KEY UPDATE `time`=VALUES(`time`);
Please see a working example here.
I would strong suggest using on duplicate key update. This starts with a unique index on user/product:
create unique index idx_recently_viewed_user_product on recently_viewed(user, product);
Then:
insert into recently_viewed(user, product, time)
values ($user, $product, $time)
on duplicate key update time = values(time);
is there a way in SQL to create the constraint that a column has to be unique, if a specific column has a specific value?
Example: the rows are not really deleted, but marked as 'deleted' in the database. And within the 'not-deleted' rows, ValueA has to be unique:
ID ValueA ValueB Deleted
-----------------------------------------------------
1 'foo' 10 0
2 'bar' 20 0
3 'bar' 30 1
4 'bar' 40 1
5 'foo' 50 0 --NOT ALLOWED
I thought of something like a CHECK constraint, however I don't know how to do this.
with SQL92 this is not possible, may be you could implement something with a trigger
Can you change the design a little bit?
It seems to me that you have a list of "thingies". For each ValueA, there's a single active "thingy" at any one time. This can best be modeled as follows:
Remove ValueA and Deleted from your main Thingies table.
Create a new table ActiveThingies with columns ValueA and ID. Protect this table by making ValueA a unique or primary key. (You may also need to make ID unique as well depending on whether a single ID can represent more than 1 ValueA).
Now, use the ActiveThingies table to control which record is current at any time. To change the active (non-deleted) record for "foo", update it's ID column in ActiveThingies.
To get your list of non-deleted items join the two tables.
With this design, however, you will lose the ability to remember the ValueA for "deleted" "thingies". If you need to remember those values, you will also need to include the ValueA column in Thingies.
There is workaround this problem - create another column deleted_on
deleted_on timestamp NOT NULL DEFAULT '0000-00-00 00:00:00'
and make unique key on both ValueA and deleted_on
UNIQUE KEY not_deleted (ValueA, deleted_on)
When soft deleting a record insert NOW() for value of deleted_on
MySQL ignores CHECK constraints, so you cannot do this in MySQL as you might in another database.
Here is a hack. Unique constraint on valueA + deleted. When deleting rows you cannot use just 1, they must be 1, 2, 3...
This at least lets you do it server-side in MySQL, but introduces a step. When marking a row for deletion, you have to first go find the max(deleted), add 1, and plug that value in when marking for deletion.
Split your table into two tables: One which has a UNIQUE constraint on ValueA and one that doesn't. Use a view+triggers to combine the two tables. Something like:
CREATE TABLE _Active (
ID INTEGER,
ValueA VARCHAR(255) UNIQUE,
ValueB INTEGER
);
CREATE TABLE _Deleted (
ID INTEGER,
ValueA VARCHAR(255), /* NOT unique! */
ValueB INTEGER
);
CREATE VIEW Thingies AS
SELECT ID, ValueA, ValueB, 0 AS Deleted FROM _Active
UNION ALL
SELECT ID, ValueA, ValueB, 1 AS Deleted FROM _Deleted;
CREATE TRIGGER _trg_ii_Thingies_Active
INSTEAD OF INSERT ON Thingies
FOR EACH ROW WHEN NOT NEW.Deleted
BEGIN
INSERT INTO _Active(ID, ValueA, ValueB)
VALUES (NEW.ID, NEW.ValueA, NEW.ValueB);
END;
CREATE TRIGGER _trg_ii_Thingies_Deleted
INSTEAD OF INSERT ON Thingies
FOR EACH ROW WHEN NEW.Deleted
BEGIN
INSERT INTO _Deleted(ID, ValueA, ValueB)
VALUES (NEW.ID, NEW.ValueA, NEW.ValueB);
END;
/* Add triggers for DELETE and UPDATE as appropriate */
(I'm not sure about the CREATE TRIGGER syntax, but you know what I mean.)