I have two columns in a row: min_value, max_value. Is there a way to do a select like:
SELECT RAND(`min_v`, `max_v`) `foo` [..]
I do realize that RAND does a different thing; the closest I came up (with help) is (RAND() * (max-min))+min, though it will produce a float number, which I'd need then to ROUND() and this is just completely wrong.
Unless anyone can suggest an alternative (which would be very useful), I will go PHP way.
Actually, ROUND((RAND() * (max-min))+min) is the best way in MySQL to do what you'd like. It is also the best way in ActionScript, JavaScript, and Python. Honestly, I prefer it to the PHP way because it is more convenient.
Because I don't know how many rows you'll be returning, I can't advise you whether it is better to use PHP or MySQL for this, but if you're dealing with a large number of values you probably are better off using MySQL.
Addendum
So, there was a question as to whether this is better in PHP or MySQL. Instead of getting into a debate on principles, I ran the following:
<pre><?php
$c = mysql_connect('localhost', 'root', '');
if(!$c) die('!');
echo mysql_select_db('test', $c)?'Connection':'Failure';
echo PHP_EOL;
echo ':::::::::::::::::::::::::BEGINNING MYSQL RAND::::::::::::::::::::::::::::::'.PHP_EOL;
$start = microtime(1);
for( $i = 0; $i < 100000; $i++ )
{
$r = mysql_query( 'SELECT ROUND(RAND() * (200-10) + 10) FROM dual' );
$r = mysql_fetch_array( $r );
}
$end = microtime(1);
echo ($end - $start) . " for MySQL select".PHP_EOL;
echo ':::::::::::::::::::::::::BEGINNING PHP RAND::::::::::::::::::::::::::::::' .PHP_EOL;
$start = microtime(1);
for( $i = 0; $i < 100000; $i++ )
{
$r = mysql_query( 'SELECT 200 AS two, 10 AS tem FROM dual' );
$r = mysql_fetch_array( $r );
$r[2]= rand($r[0], $r[1]);
}
$end = microtime(1);
echo ($end - $start) . " for PHP select".PHP_EOL;
MySQL is faster by about 2-3%.
If you use this, however (note, more columns return by MySQL):
<pre><?php
$c = mysql_connect('localhost', 'root', '');
if(!$c) die('!');
echo mysql_select_db('test', $c)?'Connection':'Failure';
echo PHP_EOL;
echo ':::::::::::::::::::::::::BEGINNING MYSQL RAND::::::::::::::::::::::::::::::'.PHP_EOL;
$start = microtime(1);
for( $i = 0; $i < 100000; $i++ )
{
$r = mysql_query( 'SELECT ROUND(RAND() * (200-10) + 10) as rd, 200 as two, 10 as ten FROM dual' );
$r = mysql_fetch_array( $r );
}
$end = microtime(1);
echo ($end - $start) . " for MySQL select".PHP_EOL;
echo ':::::::::::::::::::::::::BEGINNING PHP RAND::::::::::::::::::::::::::::::' .PHP_EOL;
$start = microtime(1);
for( $i = 0; $i < 100000; $i++ )
{
$r = mysql_query( 'SELECT 200 AS two, 10 AS tem FROM dual' );
$r = mysql_fetch_array( $r );
$r[2]= rand($r[0], $r[1]);
}
$end = microtime(1);
echo ($end - $start) . " for PHP select".PHP_EOL;
MySQL comes out behind by 3-4% (very inconsistent results) (about the same results if you don't use an array index assignment for $r[2]).
The major difference, it seems, comes from the number of records return to PHP and not the randomization system itself. So, if you need column A, column B, and a random value, use PHP. If you only need the random value, then use MySQL.
This method guarantees the same statistical probability for each value:
SELECT FLOOR((RAND() * (max-min+1))+min)
in case minimum range is 1, you can simply
SELECT FLOOR((RAND() * max_range) + 1)
in case minimum range is 0, you can even more simply
SELECT FLOOR((RAND() * max_range))
Could you do something like this?
SELECT id, (FLOOR( 1 + RAND( ) *60 )) AS timer
FROM users
LIMIT 0 , 30
See this post
Depending on how many rows you have in the table(s), using rand() in a query or subquery can be extremely slow.
You can seriously improve the speed by first putting the random value in a variable and then just using that in your query.
For example on a table with over 4 million rows...
This took over 10 minutes:
SELECT
*
FROM
`customers` `Customer`
WHERE
`id` = (
SELECT
FLOOR((RAND() * (max(`CustomerRand`.`id`) - min(`CustomerRand`.`id`) + 1)) + min(`CustomerRand`.`id`)) `random_id`
FROM
`customers` `CustomerRand`
);
While this took about 3 seconds on average:
SELECT
FLOOR((RAND() * (max(`CustomerRand`.`id`) - min(`CustomerRand`.`id`) + 1)) + min(`CustomerRand`.`id`)) `random_id`
FROM `customers` `CustomerRand` INTO #rand_id;
SELECT * FROM `customers` WHERE `id` = #rand_id;
You might even be able to put this into a stored procedure then if it's something you would want to do or re-use often. The stored procedure could then be called from PHP or Python or wherever
You can use order by rand
SELECT virtual.num
FROM (
SELECT 1 AS num UNION
SELECT 2 AS num UNION
SELECT 3 AS num
) virtual
ORDER BY RAND()
LIMIT 1
Related
<?php
$con = mysqli_connect('localhost', 'root', '', 'Materniteti');
$f = "select count(*) as f from neonatologji where gjinia=1";
$m = "select count(*) as m from neonatologji where gjinia=2";
$s = $f + $m;
$result = mysqli_query($con, $s);
$row = mysqli_fetch_assoc($result);
echo $row["s"];
$percentage = number_format( $f / $s ) * 100 . '%';
?>
I wanted to make a percentage calculation where the program selects all the female gender and saves the number in $f and all the the male gender in $m and in $s should be saved the sum of f and m. But the program doesn't recognize the $m and so the $s doesn't work.
What can I do?
There are so many issues with the given code.
Never use * with count, as you have to count only rows then an individual column is sufficient. So replace the following line:
$f = "select count(*) as f from neonatologji where gjinia=1";
to
$f = "select count(id) as f from neonatologji where gjinia=1";
Select query return ResultSet. You cannot use it directly, you have to convert it to an array by using fetch_array().
I have 15 databases 1,2,3,4, ... 15
and I have the variable $i default at 1 and each time the $i count gets to 3, $i restarts the looping from 1 again until 3 and it will stop until value from database is done counting.
$detailPsycho = mysql_query("SELECT * FROM `psycho` WHERE `flag` = 2 ") or die(mysql_error());
while($detail = mysql_fetch_array($detailPsycho)){
for($i = 1;$i<=3;$i++){
echo $detail['sequence']."&".$i." <br>";
}
}
and run over like this :/
1&1
1&2
1&3
2&1
2&2
2&3
You try to do a loop (for{}) in a loop (while{}) which is a complicated way of doing something trivial. This is the "while+for" result :
$detailPsycho = mysql_query("SELECT * FROM `psycho` WHERE `flag` = 2 ") or die(mysql_error());
i = (int) 1;
while($detail = mysql_fetch_array($detailPsycho)) {
echo $detail['sequence']."&".$i." <br>";
$i++;
if ($i > 3) $i = 1;
}
I am trying to round a decimal from a table and update another field in the same table with the new rounded value, but I just cant seem to hack it.
The rounding script works perfectly, but I am stuck trying to run the rounding script and update the database accordingly.
The table consist of over 10,000 entries, thus I request only data of a specific given date, which narrows down to about 1,200 entries at a time...
Here is my foreach loop (which works well on its own), but this is not working:
<?php
include("XXXX");
$cxn = mysqli_connect($host,$user,$password,$dbname)
or die ("Couldn't connect to server.");
$query = "SELECT `sub_hrs`, `id` FROM `attend` WHERE `date` = '$date'";
$result = mysqli_query($cxn,$query)
or die ("Couldn't execute query.");
while($row = mysqli_fetch_assoc($result))
{
extract($row);
$n = array($sub_hrs);
foreach($n as $i) {
$new[] = (fmod($i, 1) > 0.5
? sprintf("%2.f", (float) (int) $i + 0.5)
: sprintf("%2.f", (float) (int) $i)) . PHP_EOL;
$mysql_query("UPDATE `attend` SET `total_hrs` = $new WHERE `id` = $id");
}
}
You are assigning an array $new[] in below line.
$new[] = (fmod($i, 1) > 0.5
? sprintf("%2.f", (float) (int) $i + 0.5)
: sprintf("%2.f", (float) (int) $i)) . PHP_EOL;
But in query you are passing only $new variable which will not work as you will not get any value in $new variable.
$mysql_query("UPDATE `attend` SET `total_hrs` = $new WHERE `id` = $id");
Thanx for all the help guys, but I figured out that a simple query does the trick...
UPDATE `attend`
SET `total_hrs` = if((`sub_hrs` - truncate(`sub_hrs`,0)) < 0.5, truncate(`sub_hrs`,0), ((truncate(`sub_hrs`,0)) + 0.5))
WHERE `date` = '$date'
I want to show the array value $result[] from the for loop calculation. However, it shows me nothing on the page. Is there is anything wrong in the below code?
$sql= "SELECT * FROM items where itemID =3 ";
$result1= mysql_query($sql) or die (mysql_error());
while ($row= mysql_fetch_array($result1)){
$quantity[] = $row ['quantity'];
$month[] = $row ['month'];
}
$alpha = 0.3;
for($i = 1; $i > 12; $i++){
$result[$i] = ($quantity[$i] - $result[$i-1]) * $alpha + $result[$i-1];
}
foreach ($result as $key => $value ){
echo "$value";
}
Your for loop has an error. You have
for($i = 1; $i > 12; $i++)
but it should be
for($i = 1; $i < 12; $i++)
This is not directly the answer to your question, but there are few things that hasn't been mentioned that concern the way you query and process your data:
Your SELECT statement doesn't have specific order specified. Since order of records is not preserved you can get records out of correct order and get invalid calculations. Use ORDER BY (e.g. ORDER BY month) or make use of month values and extract exactly previous month's value from array(s) (if it is what you're doing in your code).
Your current code relies on the fact that the resultset from DB will contain (at least) 12 records. If for some reason it will produce less records your for loop will brake.
It's uncertain from the information in the question but it looks like you might need a year in your query unless the table contains records only for one year.
Now, you can calculate the whole thing on DB side with a query like this
SELECT i.month,
COALESCE((i.quantity - p.quantity) * 0.3 + p.quantity, 0) value
FROM items i LEFT JOIN items p
ON i.itemID = p.itemID
AND i.`year` = p.`year`
AND i.month = p.month + 1
WHERE i.itemID = 3
AND i.`year` = 2013
ORDER BY month
SQLFiddle
That's assuming (and I'm not sure about that) you actually need to read previous month's quantity values for your calculations and month column is of integer type
There is an obvious flaw in the logic. You try to get the $i index form $quantity. However, you can't be sure $quantity will have this index.
Supposing that itemId is not the primary key, I would do something like this:
$sql = "SELECT * FROM `items` WHERE `itemID` = 3";
$result1= mysql_query($sql) or die (mysql_error());
while ($row= mysql_fetch_assoc($result1)){
$quantity[] = $row ['quantity'];
}
$alpha = 0.3;
$i = 1
foreach ($quantity as $elem) {
if ($i >= 12)
break;
$result[$i] = ($elem - $result[$i-1]) * $alpha + $result[$i-1];
$i++
}
foreach ($result as $value ){
echo $value;
}
I would like to update multiple records in a MySQL table using a single query. Basically, this is a tasks table, which has assignments for different people on different dates. When these assignments are changed and submitted via the Online form there is a lot of POST data that gets submitted (pretty much all the pending assignments). I've written an algorithm that sorts through all this information and gets what I want out of it, but I'm stuck on writing the query to update the MySQL table:
// Find the modified records and save their information
$update = 0;
for ( $n = 0; $n < $total_records; $n++ )
{
if ( $_POST['update'.$n] == true )
{
$updates_arr[$update] = array( intval($_POST['user_id'.$n]), intval($_POST['task'.$n]), $_POST['date'.$n] );
$update++;
}
}
if ( $mysql_db = OpenDatabase() )
{
$query = "UPDATE tasks_tbl";
if ( $updates_arr[0] )
{
$query .= " SET task = ".$updates_arr[0][1]." WHERE user_id = ".$updates_arr[0][0]." AND date = ".$updates_arr[0][2];
}
for ( $n = 1; $n < $updates; $n++ )
{
$query .= ", SET task = ".$updates_arr[$n][1]." WHERE user_id = ".$updates_arr[$n][0]." AND date = ".$updates_arr[$n][2];
}
$result = mysql_query( $query, $mysql_db );
if ( $result )
{
$page .= "<p>Success!</p>\n\n";
}
else
{
$page .= "<p>Error: ".mysql_error()."</p>\n\n";
}
}
This is the query that is generated:
UPDATE tasks_tbl
SET task = 1
WHERE user_id = 16
AND date = 2010-05-05,
SET task = 1
WHERE user_id = 17
AND date = 2222-02-22
Any suggestions would be appreciated. Thanks.
You can generate a query like this:
UPDATE tasks_tbl SET task=1 WHERE
(user_id=16 AND date='2010-05-05') OR
(user_id=17 AND date='2010-02-22')
There are hacks to avoid using (... and ...) or (... and ...) constructs (concatenate fields and params: "concat(user_id, date) = '". $user_id. $date. "'", but they work a bit slower.
The PHP code:
for ($i = 0; !empty($_POST['update'. $i]; $i++)
if (intval($_POST['task'.$i]) == 1)
$cond[] = '(user_id='. intval($_POST['user_id'. $i]).
' and date=\''. mysql_real_escape_string($_POST['date'.$i]). '\')';
$query = 'UPDATE tasks_tbl SET task=1 WHERE '. implode(' OR ', $cond). ')';
Edit: I don't quite understand why you need to do that in a single query. How many values task can have? 1, 2, 3, or many more? With 3 values, you can use nested IF(...) functions:
UPDATE tasks_tbl SET task=if('. <imploded tasks with value 1>. ', 1, if('.
<tasks with value 2>. ', 2, if('. <tasks with 3>. ', 3,
task))) /* leave as is otherwise */
Or you may put a simple loop on the code I've given:
for ($j = 1; $j <= 3; $j++)
for ($i = 0; !empty($_POST['update'. $i]; $i++)
if (intval($_POST['task'.$i]) == 1)
$cond[] = '(user_id='. intval($_POST['user_id'. $i]).
' and date=\''. mysql_real_escape_string($_POST['date'.$i]). '\')';
mysql_query('UPDATE tasks_tbl SET task=1 WHERE '. implode(' OR ', $cond). ')');
I disagree with your architecture here, but the following should work. Use at your own risk:
UPDATE
Tasks_Table
SET
task =
CASE
WHEN user_id = 16 AND date = 2010-05-05 THEN 1
WHEN user_id = 17 AND date = 2222-02-22 THEN 1
...
END
WHERE
(user_id = 16 AND date = 2010-05-05) OR
(user_id = 17 AND date = 2222-02-22) OR
...
In your example you have task = 1 in all cases, but with the CASE statement you can change them to be what you need for each case. I'll leave the string building to you.
I would prefer to use a prepared query and loop over the data (inside a transaction if needed). That makes it simpler to understand, which is better for maintainability.
Your code smells of sql injection insecurity, too, which prepared queries would eliminate.
See: http://www.php.net/manual/en/mysqli.prepare.php or even better with PDO prepare:
Thanks for the suggestions, everyone. I ended up going with the multiple queries, as it apparently was not going to be as simple to do, as I had hoped.
foreach ( $updates_arr as $record => $data ):
$query = "UPDATE tasks_tbl";
$query .= " SET task = ".$data[1];
$query .= " WHERE task_id = ".$data[0];
$result = mysql_query( $query, $mysql_db );
if ( !$result )
{
break;
}
endforeach;
Are you looking for this:
UPDATE tasks_tbl
SET task = 1
WHERE (user_id = 16 AND date = 2010-05-05)
OR (user_id = 17 AND date = 2222-02-22)
Or you are trying to set 'task' to different values in different rows with a single statement?
The latter is just not possible
I don't think this is possible with one statement. You will need to create separate UPDATE statements:
UPDATE tasks_tbl SET task = 1 WHERE user_id = 16 AND date = 2010-05-05;
UPDATE tasks_tbl SET task = 1 WHERE user_id = 17 AND date = 2222-02-22
You can pass them into mysql_query() as one string separated by ';' if you set mysql to accept multiple queries:
Multiple queries seem to be supported.
You just have to pass flag 65536 as
mysql_connect's 5 parameter
(client_flags)