I need to pull from MYSQL a value , than change forward the value and insert in to the mysql.
for example :
$str = mysql_fetch_assoc(mysql_query('SELECT `str_id` FROM `ids` ORDER BY `num_id` DESC LIMIT 1 ')); // = aaa
$str = $str++; // aaa -> aab
// than check if "aab" key already exist
// if not , insert as key as "aab"
as for this algorithm there is a risk that this script runs from the two sides of the globe and two unique keys will be sign as "aab"..
how can i do this without risk of sign this unique key two times?
If you set up your database so that the column is unique, the MySQL table will not allow you to add the same value twice. You can then check the result of the transaction to ensure that it succeeded.
From your example it looks like you just want an incremented unique key. You should use an integer for this, which can automatically increment when you insert a new row. If you want it to be in string form just perform some basic math on it. i.e.
1 = a
2 = b
...
27 = aa
28 = ab
This is assuming you don't already have a primary key on your table, in which case I don't understand why you need the string in that form. Hopefully this helps, and I apologize if I misunderstood the question.
When using MySQL-InnoDB you should use Transactions (Provided by MySQLi and PDO) for that cause. MyISAM does not support it.
Here is the manual about transactions in PDO: http://php.net/manual/en/pdo.transactions.php
Related
I have a question that seems pretty basic but am having trouble finding the most efficient solution.
Suppose I have this table, table KEYS
KEYS
KEY_ID VALUE USED
1 123ASD 1
2 ASD234 0
3 123456 0
I want to have an API (Going call it get_key.php here) that will access the db for the last value with used=0, return the key in JSON format to be interpreted to the user via ajax, and then mark the key as used in the db.
I've seen thoughts about lock table, but my worry is that there is a script constantly generating and inserting keys into the DB while tons of users will be requesting keys.
What is the best way to achieve this while still being safe against duplicate entries being sent out, table locks causing long delays in web page delivery, and still being able to insert while retreiving?
If you are still confused, here is a basic example...
get_key.php
//not real file just pseudo
//(lock table?)
//SELECT VALUE, KEY_ID FROM `KEYS` WHERE USED = 0 LIMIT 1;
//$key = $response['VALUE']
//echo out key in json format
//$key_id = $response['KEY_ID']
//UPDATE `KEYS` SET USED = 0 WHERE KEY_ID = $key_id;
//(unlock table?)
insert_key.php
//$key = $_GET['value']
//(lock tables?)
//INSERT INTO `KEYS` (VALUE) VALUES ($key)
//(unlock tables?)
I know this setup in production setting would be extremely insecure, but trying to make as simple as possible so you can understand my question properly.
Thanks so much for your time!
Use InnoDB or any other engine which supports row-level locks. Then you only ever have to lock the one row in question that you're selecting/updating, e.g.
SELECT VALUE, KEY_ID
FROM `KEYS`
FOR UPDATE // <--- add this row
WHERE USED = 0 LIMIT 1;
... do other stuff
UPDATE `KEYS`
SET USED = 1
WHERE KEY_ID = xxx;
COMMIT;
MySQL will lock the record it finds, and then only this particular DB connection will be able to modify that record until it's unlocked or the connection is closed.
I am trying to add the value "006" to an MySql row, but it shows up as "6"! any fixes on my code ?
$id = "006";
mysql_query("INSERT INTO Table (id) VALUES ($id) ");
Thanks,
If id is a numeric column such as an integer, 006 is the same as 6 so there isn't a way to explicitly save 006 since its exactly the same as 6.
But if you want to retrieve that integer as a 3-digit, zero-padded string, you could use the LPAD function to pad it with 0's on the left side:
SELECT LPAD(id, 3, '0') as id FROM table;
Although this is not a safe way:
$id = "006";
mysql_query("INSERT INTO Table (id) VALUES ('$id') ");
I think you forgot some quotes on values, so its cast to int.
Your field needs to be a VARCHAR for that to work as you desire. You may also pad leading zeroes when you run your queries as an alternative.
I suppose that's just incorrect value (for the int field type) and cannot be stored at all.
Database intended to store data, means data without any additional formatting, which can be added at select time. That's how this thing works in general.
So, I'd suggest to store a regular int, and pad it with whatever number of zeros you wish at select time
Try to use query in mysql.
ALTER TABLE table MODIFY COLUMN id INT(3) ZEROFILL;
this may solve your question.
I'm trying to count a table row and add 1 on the outcome, I have this snippet of code.
$countQuery = "SELECT COUNT(id) FROM donations";
$outcomeQuery = mysql_query($countQuery);
$countUp = mysql_fetch_array($outcomeQuery);
$plusOne = 1;
$outcome = $countUp;
echo $outcome[0]
or die(mysql_error());
But this gives me the error:
Fatal error: Unsupported operand types
I need this so I always have a unique number that's not used by a previous donator.
You could use:
SELECT COUNT(id)+1 as IDCount FROM donations
as your query instead. This will save you any mucking about in PHP to do the math. The array you pull back will have the number that you want right off the bat.
Edit: The better alternative however is to use a column type that increments automatically. In MySQL, this is done with the syntax auto_increment in the create table syntax.
Using this, you never actually have to insert a value, but rather, you pass it a NULL as follows (assuming that ID is the field with Auto_increment on it:
insert into tableName (ID,Name) values (null, 'Fluffeh');
So you see you don't give it any values for the ID column - the database takes care of using the right number.
use simple php
$countQuery = mysql_query("SELECT id FROM donations");
$count=mysql_num_rows($countQuery);
$count+=1;
It's dangerous to rely on COUNT to give you a unique number. What happens if two processes execute this query, and then both try and commit: you suddenly have the same value twice.
It would be much safer to implement some kind of sequence function independent of your table contents. This link shows one possibility:
http://forums.mysql.com/read.php?61,143867,238482#msg-238482
This question is for a MySQL database. I suggest you use the AUTO INCREMENT field type.
As you are using PHP, if you need to know the id after inserting a record, use:
mysql_query("INSERT INTO mytable (1, 2, 3, 'blah')");
$id = mysql_insert_id();
See mysql_insert_id().
Using
4 random generated numbers to make 100% sure there are no duplicates
will not make 100% sure there are no duplicates. Don't re-invent the wheel. This is how the problem of ensuring unique incrementing identifiers are used has been solved, you don't need the embarrassment of a homebrew solution that doesn't always work.
I have an array of data that generates unique data on the fly in a manor of speaking. It's actually an array with 5 hashes.
What I want to do is a basic select query with a where clause that checks each via OR basically a one line query rather than a query for each array item.
I'm attempting to ensure that no one hash that enters the db is the same as another which I know the probability is virtually null to that actually happening but it's a possibility none the less, safer than sorry is my perspective on the matter
Anyway the query I'm thinking of makes no sense as if a match is found the query will result in such what I wanna do is from the original array find the one that's not found and use it where if all 5 aren't found I'll just randomly pick one I guess in the end I want to form a result that is 1 to 5 in a new array so I can randomly pick from that result
Is this possible or would it just be easie to cycle over each one with a songle query?
"SELECT
CASE hashes.hash
WHEN $hashes[0] THEN 0
WHEN $hashes[1] THEN 1
WHEN $hashes[2] THEN 2
WHEN $hashes[3] THEN 3
...
END
FROM hashes WHERE hashes.hash IN(".implode($hashes).")"
This should tell you exactly which of the hashes you sent to the server have been found on the server.
The result set would be the index keys (0, 1, 2, 3) of the array that generated the query.
If you sent a query based on an array of 100 hashes and you get a result set of 99 hashes, that means at least one hash was not found in the db.
You could cycle through the result set like this:
while($row = $pdo->fetch()) {
$index = $row[0] // first column of the result set
unset($hashes[$index]);
}
When while finishes the only hashes left in the array should be the ones that weren't found in the database.
My opinion is that it would be easier to to cycle over each one with a single query. From what you say there appears to be no major benefit in doing it all at once.
In that case I would suggest:
alter table myTable create id_bkp int;
update myTable set id_bkp=account_id;
update myTable set account_id=56 where id_bkp=100;
update myTable set account_id=54 where id_bkp=56;
alter table myTable drop id_bkp;
Of course that will depend on what DB system you are using.
Do you mean something like this?
$sql = "SELECT * FROM `table` WHERE `field` = ";
$where_string = "'" . implode("' OR `field` = '",$my_array) . "'";
$sql .= $where_string;
You could use:
$my_array = array_unique($my_array);
To remove duplicate values.
Here is my table:
Table Name: UserLinks
Link_ID User_1 User_2
1 234325 100982
2 116727 299011
3 399082 197983
4 664323 272351
Basically, in this table a duplicate value is:
Link_ID User_1 User_2
1 232 109
2 109 232
I have looked around and found that I should use INSERT IGNORE to prevent duplicate entries, but I am not sure how to write a query that considers that the relationship between User_1 and User_2 is the same as between User_2 and User_1.
Any advice/help is really appreciated.
Thats a bit nasty, a commutative relationship between the 2 fields, but a unique index will not help given the values can be either way around.
If you could alter the code / data to ensure that the lower value of the ids was always placed in the user_1 field, that would at least then let the unique index work - but its a bit nasty.
Alternatively if the insertion is set based (e.g. not a row at a time but a set of rows) you could join to the existing data and anti-join based on both ways round e.g. :
(existing.user_1 = new.user_1 and existing.user_2 = new user_2)
OR (existing.user_1 = new.user_2 and existing.user_2 = new user_1)
and in the where clause check to ensure no match was made (the anti part of the join)
where existing.link_id is null
That wouldn't be efficient for row at a time insertion though.
How accurate do you need it. You could just create a unique index (or primary key) that is the hash of the 2 values xor'd together.
Something like primary key (md5(user_1) xor md5(user_2)).
Because "md5(232) xor md5(109)" will always equal to "md5(109) xor md5(232)". It does no matter on the order.
This will have a small chance of collision if you have a lot of records (like millions or billions) but otherwise, it should work.
You might need to check on the sql for this, as I did not test if SQL allows primary key to be generated like this.
This way, you do not need to add any additional check when inserting or updating as the unique constrant will do the checking for you.