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.
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'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 was looking for a way of creating a collaborative translation widget. So I have a mysql database and table (called translations), and a little script to allow users to translate one page at a time.
But I'm not quite convinced with my script. I don't think it's efficient enough. First, the mysql gets all the rows with the empty 'en' column, and then a single one of them is showed by screen through a while. Is there any other way of doing this? This is the code:
//Retrieve all the data from the "translations" table
$result = mysql_query("SELECT * FROM translations WHERE en IS NULL OR en=''") or die(mysql_error());
$Randnum=rand(0,mysql_num_rows($result)-1); //Gets a random number between 0 and the maximum number of rows
$i=0; //Start to 0
while($Col = mysql_fetch_array($result)) //While there are rows to evaluate
{
if ($i==$Randnum)
{
echo "\"".$Col['es']."\"<br><br>Translate it to English: <br>";
}
$i++;
}
I was looking for something like "echo $Col[$Randnum]['es']" or "echo $Col.$Randnum['es']" instead of using the whole while loop to print a single random row. How can I implement this? If it's just a matter of optimization. If you could come with an script or idea to assign to $Col just ONE row with a random number and the empty 'en' col, that'd be even better! (I think it's not possible this last bit). The 'en' row is text so I don't know how to implement other methods I've seen around as they use number with ORDER BY.
You can use ORDER BY RAND() LIMIT 1 in your query to fetch a single random row from the database.
Make it at query side
SELECT * FROM translations WHERE en IS NULL OR en='' ORDER BY rand() LIMIT 0,1
There are a few ways of doing this.
#ThiefMaster's answer will work - but "order by rand()" has pretty major performance problems on large tables. So, I'd populate your table with sample data of roughly the size you want to be able to grow to, and test the performance. If it's not a problem, leave it as it is - premature optimization is the root of all evil!
There are some alternatives; they rely on running two, separate queries; however, assuming you've got indices, that shouldn't be a problem.
Reworked for your scenarion, this becomes:
mysql_query('SELECT #count := COUNT(*) FROM translations WHERE en IS NULL OR en=''');
mysql_query('SET #offset = CONVERT(FLOOR(RAND() * #count), SIGNED)');
mysql_query('PREPARE mystatement FROM "SELECT * FROM translations WHERE en IS NULL OR en='' LIMIT ?, 1"');
$res = mysql_query('EXECUTE mystatement USING #offset');
$row = mysql_fetch_assoc($res);
print_r($row);
I want to add 1 to the value of the previous row for hit_count, but I'm afraid doing it may not be safe if multiple queries are being run quickly (i.e. the page is being loaded several times a second - this is for a web-app I'm making, and so I want to make sure any amount of page loads is supported well).
Here's what I had in mind:
$result = mysql_query("SELECT * FROM rotation");
$fetch = mysql_fetch_assoc($result);
$update_hit = $fetch['hit_counter']+1;
$query = "INSERT INTO rotation (hit_counter, rotation_name) VALUES ('$update_hit', '$rotation_name')";
$result = mysql_query($query);
I thought about setting the hit_counter column to a UNIQUE KEY, but I don't know what else I'd do after that.
I would use AUTO_INCREMENT but the problem is, I need the actual hit_counter value within the rest of the script.
Any ideas, comments, advice would be greatly appreciated!
Edit: I used hit_count and hit_counter, was a typo. Updated to avoid any confusion.
You can use the DUPLICATE KEY functionality when you make name + counter a unique value:
INSERT INTO rotation SET hit_counter = 1, rotation_name= 'name'
ON DUPLICATE KEY UPDATE hit_counter = hit_counter + 1
Performance wise (and if your requirements allow it) I advice pushing updates in bulk (per 100 hits) using a caching mechanism like f.e. memcached.
You could use AUTO_INCREMENT, if you need the inserted id within the rest script, you can use mysql_insert_id to get it.
This is what i am doing now : - in PHP
foreach($array as $value)
{
$query = select abc from tblname where colname =" .$value.
// fire query
}
then i create array of these values and display accordingly.
The PROBLEM: -
I have applied foreach, which fires the query every time it encounters a value in the array.
result, if i have 10 values in my array it fires 10 queries. and uses network 10 times, result slow output.
What i want -
I want to give the array to a stored procedure which shall give me a resultset which will have the outputs corresponding to all the elements in the array.
I know this can be done but do not know how.
the mysql doesnot take arrays as datatype.
the result shall be that network shall be used only once, despit of any number of values in the array.
LIKE -
StoredProcedure(inputMysqlARRAY) // not possible, need a workaroung
{
// fire simple select(same) query for each value.
}
then call this stored procedure from PHP and input array. // need workaround.
You just have to be smarter about your calls. For instance, keeping cached DB objects around and that sort of thing.
Without knowing more about your code (your question is fairly garbled), it seems that if your query is something like this:
$query = "select abc from tblname where colname =" .$value; // run 10 times.
You really just need to write smarter code:
$values = array(); // Now, populate this array.
// When you're done, run the query:
$query = 'select abc from tblname where colname IN (\''.implode('\',\'', $values).'\')';
Generally, we refer to this as Dynamic SQL and is the underpinning for how things are typically done today. A stored procedure (or, based on how I read your question, stored function) is useful at times, but is somewhat antiquated as a first-order methodology for interfacing with SQL. The DB guys still sometimes swear by it, but I think that even they are fairly well in consensus that smarter queries are always better.