Unique constraint, how to avoid duplicates - php

According to my previous Query that post i have a table that looks like this:
|| *nid* || *language* ||
|| 8 || Chinese ||
|| 8 || Portuguese ||
|| 8 || German |
In which 'nid' and 'language' have a unique constraint.
With this setup how can i make sure that the there wont be any duplicate when i try to insert a new row ?
EDITED
I am guessing I should try to make a query such as:
SELECT * FROM lang WHERE nid = $nid AND language = $lang
If this return FALSE then i know i can now insert my data. Is this correct ?

Enforce the unique constraint by creating a unique key:
ALTER TABLE the_table
ADD UNIQUE INDEX nid_language_unique (nid, language);
This constraint forbid two rows having the same nid and language.
Any query attempting to violate the constraint will fail.
As you want to ignore errors (and still abort the query), you can use INSERT IGNORE and UPDATE IGNORE:
INSERT IGNORE INTO the_table (nid, language) VALUES (8, 'Chinese')
/* row not inserted and no error */

If you have actually established a unique constraint in the database then MySQL will not let you insert the second row. The statement will raise an exception. You can trap and ignore that in your code. If you're not interested in whether the row was added or not, you can use the IGNORE keyward in the MySQL INSERT INTO command and the row will either be added (if not there) or the command will complete without an error.

SELECT nid, language FROM lang WHERE nid = $nid AND language = $lang
If this return FALSE then i know i can now insert my data. Is this correct ?
Yes, but you need to write:
$nid = mysql_real_escape_string($_POST['nid']);
$lang = mysql_real_escape_string($_POST['lang']);
$query = SELECT nid, language FROM lang WHERE nid = '$nid' AND language = '$lang'
// notice the quotes ^ ^ ^ ^
If you forget these your query give an error (and be at risk from SQL-injection).
If you have a unique constraint, you can just go ahead and insert the data, because MySQL will do the above test for you.

You can use a counter in your code (not SQL, but the one you use to use SQL, like PHP, or else)
You can use MySQL max function and add one (like max(nid)+1 (but don't remember about MySQL's max function))
You can use a random number with 10 characters (so you'd would have a really really low risk to go into an error)
I used the first and last way many times.
And if you want to be sure that you won't have a duplicate, use the solutions from your last posts. Stuff like UNIQUE constraint will prevent you to insert twice the same nid or language (thus, if you don't handle it, your program will crash).

Related

ON DUPLICATE KEY UPDATE - Condition WHERE vs CASE WHEN vs IF?

I am refering to this post. I am stuck with a problem I can't resolve. I try to insert multiple rows with a php script into a MySQL database. I don't succeed in updating the whole thing using ON DUPLICATE KEY UPDATE and using a WHERE condition (at the end of the code below) I would like to use to update only an entry has been modified recently:
// for information (used in a foreach loop):
$args[] = '("'.$row['lastname'].'", '.$row['phone'].', "'.$row['lastModification'].'")';
// then:
$stringImplode = implode(',', $args);
// Where I am stuck - WHERE statement:
$sql = $mysqli->query('INSERT INTO table_name '. (lastname, phone, timestamp) .' VALUES '.$stringImplode .'ON DUPLICATE KEY UPDATE lastname=VALUES(lastname), phone=VALUES(phone) WHERE timestamp > VALUES(lastModification);
Everything works fine except I cannot set any WHERE condition at this point that involves multiples entries. Maybe the WHERE statement in this case is not intended to refer to a condition in this statement.
I was told to try with a database procedure using a JOIN statement and a temporary table with first all my entries and then querying some conditions. But I have to admit I don't understand very well how I could leverage such a table to update an other table.
Is there an easy and lovely way to use a "CASE WHEN" or an "IF" statement in this case?
Would something like
INSERT INTO ... ON KEY DUPLICATE UPDATE lastname = VALUES(lastname), phone = VALUES(phone)
CASE WHEN (timestamp > VALUES(lastModification)) THEN do nothing ...
or
...ON KEY DUPLICATE UPDATE... IF (timestamp > VALUES(lastModification)) ...
If anyone could help me, I would be very grateful.
EDIT: Since I will have many variables, could it be used in this way:
INSERT INTO ... ON KEY DUPLICATE UPDATE
IF(timestamp > VALUES(timestamp),
(
name = VALUES(name),
number = VALUES(number),
timestamp = VALUES(timestamp)
....many other variables
),
(
name = name,
number = number,
timestamp = timestamp
....many other variables)
)
You can use simple IF function in value like this:
INSERT INTO ... ON KEY DUPLICATE UPDATE
name = VALUES(name),
number = VALUES(number),
timestamp = IF(timestamp > VALUES(timestamp), VALUES(timestamp), timestamp)
If condition is not met, it will update timestamp with the same timestamp which already exists. It does not matter, because update to same values is optimized before it is even executed, so MySQL will not make real update. You should not afraid of some performance penalty.
EDIT:
IF works likes this:
IF(condition, returned when true, returned when false)
Maybe you need to switch those two arguments to fit your condition like you want.

Convert SQL UPDATE statement to php with if else condition (codeigniter)

I want to make php code with SQL Update Statement in Codeigniter.
If I execution code in Codeigniter, the data in database will be updated too.
I want to update one column (ID_STATUS) but with several condition.
The connection column 'ID_STATUS' with column 'lama' and 'estimasi'
My table name is "pelayanan".
ID_STATUS is PK from table "status".
So, Column ID_STATUS in table "pelayanan" is foreign key from table "status".
I tried with this query, but, It isn't if else condition yet.
condition 1 :
UPDATE `dbhpl`.`pelayanan`
SET `pelayanan`.`ID_STATUS` = '1'
WHERE `pelayanan`.`LAMA` <> `pelayanan`.`ESTIMASI`;
condition 2:
UPDATE `dbhpl`.`pelayanan`
SET `pelayanan`.`ID_STATUS` = '2'
WHERE `pelayanan`.`LAMA` = `pelayanan`.`ESTIMASI`;
That is the query on mysql. But I want to convert that query to php code (Codeigniter).
How come It will be?
your first query is
UPDATE `dbhpl`.`pelayanan`
SET `pelayanan`.`ID_STATUS` = '1'
WHERE `pelayanan`.`LAMA` <> `pelayanan`.`ESTIMASI`;
convert it as follows:
$update_data=array('ID_STATUS'=>'1');
$this->db->where('LAMA <>','ESTIMASI');
$this->db->update('pelayanan',$update_data);
your second query is
UPDATE `dbhpl`.`pelayanan`
SET `pelayanan`.`ID_STATUS` = '2'
WHERE `pelayanan`.`LAMA` = `pelayanan`.`ESTIMASI`;
convert it as follows:
$update_data=array('ID_STATUS'=>'2');
$this->db->where('LAMA','ESTIMASI');
$this->db->update('pelayanan',$update_data);
I have remove database name. database name will be selected in connection and and did required to mentioned it here.
condition 3:
a. both LAMA and ESTIMASI are null.
b. LAMA is null
c. ESTIMASI is null
If you want to update all rows in the table, based on the values of LAMA and ESTIMASI, you could do that in one fell swoop with one UPDATE statement.
UPDATE `dbhpl`.`pelayanan` p
SET p.`ID_STATUS`
= CASE
WHEN p.`LAMA` = p.`ESTIMASI` THEN '2'
WHEN p.`LAMA` <> p.`ESTIMASI` THEN '1'
WHEN p.`LAMA` IS NULL AND p.`ESTIMASI` IS NULL THEN p.`ID_STATUS`
WHEN p.`LAMA` IS NULL THEN p.`ID_STATUS`
ELSE p.`ID_STATUS`
END
Note that assigning the current value of the ID_STATUS column back to the ID_STATUS column results in "no update".
Since the last two WHEN conditions return the same values as the ELSE, those could be removed. These were included just to illustrate possible handling of condition 3.
One small difference with this vs. the original is that it will attempt tto update every row in the table, including rows that have a NULL value in LAMA and/or ESTIMASI. That means any UPDATE triggers will be fired for those rows. To get exactly the same result as the original, you'd need to include a WHERE clause that excludes rows where LAMA is null or ESTIMASI is null. For example:
WHERE p.`LAMA` IS NOT NULL
AND p.`ESTIMASI` IS NOT NULL
As far as how to accomplish this same thing in PHP, someone else may be able to answer that. Personally, I'd just do it one SQL operation.
The ANSI-standard syntax is a bit verbose. A MySQL specific version that accomplishes the same thing is a bit shorter:
UPDATE `dbhpl`.`pelayanan` p
SET p.`ID_STATUS` = IFNULL((p.`LAMA`=p.`ESTIMASI`)+1,p.`ID_STATUS`)
FOLLOWUP
If LAMA and ESTIMASI are defined as NOT NULL, then you wouldn't have to deal with condition 3. (In the more general case, we don't necessarily have that guarantee, so I think it's better pattern to account for those conditions, even if they won't ever happen in our particular case.
For CodeIgniter ActiveRecord, you'd could try something like this:
$this->db
->set('ID_STATUS', 'IFNULL((`LAMA`=`ESTIMASI`)+1,`ID_STATUS`)', FALSE)
->update('`dbhpl`.`pelayanan`');

INSERT only if both colomns are not duplicate

DELETE FROM RelationsAuthors WHERE MainId = :MainId AND AuthorId NOT IN (:authorarray)
The above code will delete anything that is not in authorarry and where MainId equals a specific value.
After the deletion I would like to insert the values of authoarray into the database if they do not exist without getting any errors.
*with using foreach $_POST['AuthorId']:
INSERT INTO RelationsAuthors (Id,MainId,AuthorId) VALUES('',:MainId,:AuthorId)
However I would like to add to my code that I need to INSERT only WHERE (MainId = :MainId AND AuthorId = :AuthorID) does not exist. How can I do that?
First, create a unique index on the two fields so the database will prevent duplicates for you:
create unique index idx_RelationsAuthors_MainId_AuthorId on RelationsAuthors(MainId, AuthorId);
Then the insert will fail with an error if you have duplicates. You can have this error ignored in a few ways. My preferred way is:
INSERT INTO RelationsAuthors (MainId, AuthorId)
VALUES(:MainId, :AuthorId)
ON DUPLICATE KEY UPDATE MainId = VALUES(MainId);
This will specifically ignore duplicate key errors, but other problems will still generate an error (if appropriate). Note I removed the first column. I'm guessing from the syntax that it is an auto-incremented id, so you don't need to include it in the insert statement at all.

php incrementing while loop

$blanknumber = $_POST["blankstartnumber"];
while ($blanknumber <= ($_POST["blankendnumber"] ))
{
echo "$blanknumber";
$blankid = $blanknumber;
$query = "INSERT INTO blank (Blank_ID) VALUES ('$blankid')";
mysql_query($query,$con);
$blanknumber++;
}
So the values are added into the database. Lets say if I have the starting number at 1 and ending at 5. It will all the those values, but it's still trying to add more into the database. I also tried adding an IF statement aswell. if ($blanknumber != $_POST["blankendnumber"])
12345 Error: Duplicate entry '5' for
key 'PRIMARY'
Make sure your $POST value is an integer; by default, I believe it will be cast as a string.
$_POST['varName'] = (int) $_POST['varName'];
edit:
$blanknumber = $_POST["blankstartnumber"];
while ($blanknumber <= ($_POST["blankendnumber"] ))
This should only execute once, since you're setting both comparison variables equal. Definitely 2x check your code.
The database error indicates that Blank_ID is your primary key for that table, and you'd already inserted a 5 into the row. A primary key's values can exist only once in the entire table - duplicates are forbidden (if they were allowed, it wouldn't be a primary key anymore).
If your while loop isn't ending, I'd suggest dumping out both the blankendnumber and blankstartnumber before the loop starts, making sure you've got the right values in there.
It looks like it's actually functioning properly, but you might not have tidy'ed up your db table prior to running. If your output was:
123455 Error: Duplicate entry '5'...
Then, you'd have a programming error, as 5 is getting run twice. Instead, I think you already have data in the blank table that causes a conflict.
Edit: to automatically have MySQL handle the duplicate key error gracefully, you can use the ON DUPLICATE KEY clause to update the row.
INSERT INTO blank (Blank_ID) VALUES (5) ON DUPLICATE KEY UPDATE mod_date = NOW();

mysql if word match statement

how do i save the data, if
1) the word match Pros, it will be saved to t_pros column
2) the word that not match Pros, it will be saved to t_others column
i heard i can use mysql CASE statement, but dont know how to use it?
table pro:
id t_pros t_others
------------------------
1 Pros 1x
2 Pros 2x
3 voucher
<input type="text" id="t_pros">
$db->query("INSERT INTO pro(t_pros,t_others) VALUES($t_pros, $t_pros)");
So in each row only one of the two columns ever has a value?
In that case, how about:
$column = (preg_match('/^Pros/i', $_POST['t_pros'])) ? 't_pros' : 't_others';
$t_pros = mysql_real_escape_string($_POST['t_pros']);
$db->query("INSERT INTO pro($column) VALUES ($t_pros)");
That is, pick which column based on whether the value begins with 'Pros' or not (just as you indicated), and then just insert into that column, using MySQL's default value (normally NULL) for the other.
First, your input field needs the attribute name="t_pros".
Secondly, this code is open to SQL Injection - read up on it.
The query might look like this:
INSERT INTO pro(t_pros,t_others) VALUES(IF($t_pros = 'Pros', 'Pros', NULL), IF($t_pros = 'Pros', NULL, $t_pros))"
But again, this is not safe. Use mysql_real_escape_string around all variables in your SQL query, or use prepared statements.
if ($t_pros == 'Pros')
$t_pros_col = $t_pros;
else
$t_others_col = $t_pros;
$db->query("INSERT INTO pro(t_pros,t_others) VALUES($t_pros_col, $t_others_col)");

Categories