Does replace into have a where clause? - mysql

I'm writing an application and I'm using MySQL as DBMS, we are downloading property offers and there were some performance issues. The old architecture looked like this:
A property is updated. If the number of affected rows is not 1, then the update is not considered successful, elseway the update query solves our problem.
If the update was not successful, and the number of affected rows is more than 1, we have duplicates and we delete all of them. After we deleted duplicates if needed if the update was not successful, an insert happens. This architecture was working well, but there were some speed issues, because properties are deleted if they were not updated for 15 days.
Theoretically the main problem is deleting properties, because some properties are alive for months and the indexes are very far from each other (we are talking about 500, 000+ properties).
Our host told me to use replace into instead of deleting properties and all deprecated properties should be considered as DEAD. I've done this, but problems started to occur because of syntax error and I couldn't find anywhere an example of replace into with a where clause (I'd like to replace a DEAD property with the new property instead of deleting the old property and insert a new to assure optimization). My query looked like this:
replace into table_name(column1, ..., columnn) values(value1, ..., valuen) where ID = idValue
Of course, I've calculated idValue and handled everything but I had a syntax error. I would like to know if I'm wrong and there is a where clause for replace into.
I've found an alternative solution, which is even better than replace into (using simply an update query) because deletes are happening behind the curtains if I use replace into, but I would like to know if I'm wrong when I say that replace into doesn't have a where clause. For more reference, see this link:
http://dev.mysql.com/doc/refman/5.0/en/replace.html
Thank you for your answers in advance,
Lajos Árpád

I can see that you have solved your problem, but to answer your original question:
REPLACE INTO does not have a WHERE clause.
The REPLACE INTO syntax works exactly like INSERT INTO except that any old rows with the same primary or unique key is automaticly deleted before the new row is inserted.
This means that instead of a WHERE clause, you should add the primary key to the values beeing replaced to limit your update.
REPLACE INTO myTable (
myPrimaryKey,
myColumn1,
myColumn2
) VALUES (
100,
'value1',
'value2'
);
...will provide the same result as...
UPDATE myTable
SET myColumn1 = 'value1', myColumn2 = 'value2'
WHERE myPrimaryKey = 100;
...or more exactly:
DELETE FROM myTable WHERE myPrimaryKey = 100;
INSERT INTO myTable(
myPrimaryKey,
myColumn1,
myColumn2
) VALUES (
100,
'value1',
'value2'
);

In your documentation link, they show three alternate forms of the replace command. Even though elided, the only one that can accept a where clause is the third form with the trailing select.
replace seems like overkill relative to update if I am understanding your task properly.

Related

Unique fields on mySQL table - generating promo codes

I am developing a PHP script and I have a table like this:
TABLE_CODE
code varchar 8
name varchar 30
this code column has to be a code using random letters from A to Z and characters from 0 to 9 and has to be unique. all uppercase. Something like
A4RTX33Z
I have create a method to generate this code using PHP. But this is a intensive task because I have to query the database to see if the generated code is unique before proceeding and the table may have a lot of records.
Because I know mySQL is a bag of tricks but not having advanced knowledge about it now, I wonder if there's some mechanism that could be built in a table to run a script (or something) every time a new record in created on that table to fill the code column with a unique value.
thanks
edit: What I wonder is if there's a way to created the code on-the-fly, as the record is being added to the table and that code being unique.
Better generate these codes in SQL. This is 8-character random "Promo code generator":
INSERT IGNORE INTO
TABLE_CODE(name, code)
VALUES(
UPPER(SUBSTRING(MD5(RAND()) FROM 1 FOR 8)), -- random 8 characters fixed length
'your code name'
)
Add UNIQUE on code field as #JW suggested, and some error-handling in PHP, because sometimes generated value may be not UNIQUE, and MySQL will raise error in that situation.
Adding a UNIQUE constraint on the code column is the first thing you would need to do. Then, to insert the code I would write a small loop like this:
// INSERT IGNORE will not generate an error if the code already exists
// rather, the affected rows will be 0.
$stmt = $db->prepare('INSERT IGNORE INTO table_code (code, name) VALUES (?, ?)');
$name = 'whatever name';
do {
$code = func_to_generate_code();
$stmt->execute(array($code, $name));
} while (!$stmt->rowCount()); // repeat until at least one row affected
As the table grows the number of loops may increase, so if you feel it should only try three times, you could add it as a loop condition and throw an error if that happens.
Btw, I would suggest using transactions to make sure if an error occurs after the code generation, rolling back will make sure the code is removed (can be reused).

count(*) on mysql giving me value 0

select count(*) FROM antecedente_delito WHERE rut_polichile = NEW.rut_polichile
this statement is giving de value 0, when it should give me 18 :/ ive been trying a lot to find any bug in it.
Here's the working solution that I mocked up using/changing your code in SqlFiddle. http://sqlfiddle.com/#!2/ac2e9/1
To trouble shoot this, I would view your actual values and verify that NEW. is returning what you think it should. Sometimes it may be doing some trims or removal of special characters, especially the _ and % signs are likely to stripped in subprocedures.
I would start with the query:
select top 50 rut_polichile, NEW.rut_plichile FROM antecedente_delito
If the issue is not obvious from that add in a varbinary check:
select top 50 cast( rut_polichile as varbinary), cast(NEW.rut_plichile as varbinary) from antecedente_delito
If the table only has 18 records, then you should be good to go with the above troubleshooting, but if there is more data, I would suggest limiting your results from the above by the rowid or other identifier in a where statement.
It's not the answer, but I hope it helps you find the answer.
The SELECT privilege for the subject table if references to table columns occur via OLD.col_name or NEW.col_name in the trigger definition.
but in your trigger i can't see any trigger definition. so try without NEW.
for more info: http://www.sqlinfo.net/mysqldocs/v51/triggers.html or
http://bugs.mysql.com/bug.php?id=31068

Update MySQL without specifying column names

I want to update a mysql row, but I do not want to specify all the column names.
The table has 9 rows and I always want to update the last 7 rows in the right order.
These are the Fields
id
projectid
fangate
home
thanks
overview
winner
modules.wallPost
modules.overviewParticipant
Is there any way I can update the last few records without specifying their names?
With an INSERT statement this can be done pretty easily by doing this:
INSERT INTO `settings`
VALUES (NULL, ...field values...)
So I was hoping I could do something like this:
UPDATE `settings`
VALUES (NULL, ...field values...)
WHERE ...statement...
But unfortunately that doesn't work.
If the two first columns make up the primary key (or a unique index) you could use replace
So basically instead of writing
UPDATE settings
SET fangate = $fangate,
home = $home,
thanks = $thanks
overview = $overview,
winner = $winner,
modules.wallPost = $modules.wallPost,
modules.overviewParticipant = $modules.overviewParticipant
WHERE id = $id AND procjectId = $projectId
You will write
REPLACE INTO settings
VALUES ($id,
$projectId,
$fangate,
$home,
$thanks
$overview,
$winner,
$modules.wallPost,
$modules.overviewParticipant)
Of course this only works if the row already exist, otherwise it will be created. Also, it will cause a DELETE and an INSERT behind the scene, if that matters.
You can't. You always have to specify the column names, because UPDATE doesn't edit a whole row, it edits specified columns.
Here's a link with the UPDATE syntax:
http://dev.mysql.com/doc/refman/5.0/en/update.html
No, it works on the INSERT because even if you didn't specify the column name but you have supplied all values in the VALUE clause. Now, in UPDATE, you need to specify which column name will the value be associated.
UPDATE syntax requires the column names that will be modified.
Are you always updating the same table and columns?
In that case one way would be to define a stored procedure in your schema.
That way you could just do:
CALL update_settings(id, projectid, values_of_last_7 ..);
Although you would have to create the procedure, check the Mysql web pages for how to do this, eg:
http://docs.oracle.com/cd/E17952_01/refman-5.0-en/create-procedure.html
I'm afraid you can't afford not specifying the column names.
You can refer to the update documentation here.

DBIx::Class update only one row

I am using DBIx::Class and I would like to only update one row in my table. Currently this is how I do it:
my $session = my_app->model("DB::Session")->find(1);
$session->update({done_yn=>'y',end_time=>\'NOW()'});
It works, but the problem is that when it does find to find the row, it does this whole query:
SELECT me.id, me.project_id, me.user_id, me.start_time, me.end_time, me.notes, me.done_yn FROM sessions me WHERE ( me.id = ? ): '8'
Which seems a bit much when all I want to do is update a row. Is there anyway to update a row without having to pull the whole row out of the database first? Something like this is what I am looking for:
my_app->model("DB::Session")->update({done_yn=>'y',end_time=>\'NOW()'},{id=>$id});
Where $id is the WHERE id=? part of the query. Does anyone know how to do this? Thanks!
You can run update on a restricted resultset which only matches this single row:
my_app->model("DB::Session")->search_rs({ id=> 1 })->update({done_yn=>'y',end_time=>\'NOW()'});
I suggest you use a DateTime->now object instead of literal SQL for updating the end_time column because it uses the apps servers date and time instead of the database servers and makes your schema more compatible with different RDBMSes.
Do you have a check if the row was found to prevent an error in case it wasn't?
You might want to use update_or_create instead.
You could use the "columns" attribute:
my $session = my_app->model("DB::Session")->find(1, {columns => "id"});

MySQL add prefix to field table-wide

Basically I just decided to switch my primary ID to a "source" field, as I will be importing stuff from multiple sources. Now I'd like to make it clear where things come from, as such I'd like to add a prefix to it, as to be portalname:formerID. I've tried
UPDATE pics SET source='nk:'+source WHERE 1=1
UPDATE pics SET source='nk:'+source WHERE faces > 0 (matches all records)
but every time phpMyAdmin returns 0 row(s) affected. ( Query took 0.0056 sec )
Any idea?
Use CONCAT() ( http://dev.mysql.com/doc/refman/5.0/en/string-functions.html#function_concat ) to concatinate strings, not "+".
you may try to omit the where clause altogether.
UPDATE pics SET source= concat('nk:',source )
or better yet, add a new column 'portal_name' and populate that seperately.