MySQL: applying a random sort on multiple columns
In order to have a well scrambled table (for a psychological experiment), I'd like to sort each column of my array by RAND(). Althrough this code works:
SELECT Sort.Variable1, Sort.Variable2 FROM Sort ORDER BY Variable1, Variable2 ASC LIMIT 0 , 30
replacing "ASC" by "RAND()" make the query fail. Can someone give me an advice (even a solution with PHP) ?
Thanks
Edit:
Thanks to all your responses, I finally did it. Here's my PHP code for this (and sorry for the old-fashioned-not-brand-new-PDO-queries). Even if it's maybe useless, I post it:
$i=0;
//Describe to retrieve variables' names
$sqlCol= 'DESCRIBE Sort';
$sqlCol= mysql_query($sqlCol);
while ($res=mysql_fetch_array($sqlCol)) {
$var[$i]=$res['Field'];
$i++;
}
$NbCol=mysql_num_rows($sqlCol); //Number of column to shuffle
// Number of items for each column
$sqlCount= 'SELECT COUNT(*) FROM Sort';
$req2= mysql_query($sqlCount) or die ('Err'开发者_如何学C);
$NbLignes= mysql_result($req2,0,0) or die ();//Number of rows
//Data array
$sql= "SELECT * FROM Sort";
$req= mysql_query($sql) or die ('Err');
$sort=mysql_fetch_array($req);
for($i=0;$i<$NbCol;$i++) {
${'sql'.$i}='SELECT * FROM Sort ORDER BY RAND()';
${'input'.$i} = mysql_query(${'sql'.$i});
while(${'array'.$i}=mysql_fetch_array(${'input'.$i})) {
$bigArray[$i][]=${'array'.$i}[$i];
}
}
for($i=0;$i<$NbLignes;$i++) {
echo '<div id="q'.$i.'"style="margin-bottom: 50px; float:left">Question '.($i+1);
echo '<ul id="sortable'.$i.'" class="sortable">';
for($j=0;$j<$NbCol;$j++) {
echo '<li class="ui-state-default" id="'.$var[$j].$i.'" name="'.$var[$j].$i.'">'. $bigArray[$j][$i].'</li>';
}
echo '</ul></div>';
}
Using ORDER BY RAND()
won't randomize columns - it will randomize rows.
To randomize each column separately in SQL you can:
- create a result set for each column separately
- randomize the order of each of them
- join the columns by row number
Unfortunately the MySQL development team haven't yet implemented ROW_NUMBER which would have made this task easy, but you can workaround it by simulating ROW_NUMBER using variables:
SELECT
Column1,
Column2
FROM
(
SELECT Column1, @rn1 := @rn1 + 1 AS rank
FROM Table1, (SELECT @rn1 := 0) vars
) T1
JOIN
(
SELECT Column2, @rn2 := @rn2 + 1 AS rank
FROM Table1, (SELECT @rn2 := 0) vars
ORDER BY RAND()
) T2
ON T1.rank = T2.rank
Here is one possible method to do what you want using PHP. In the example code, I generate a list of numbers and place them in an array. You will need to grab the list from your database.
<?php
// Create 20 rows.
$rows = 20;
// Create an empty array to hold sorted values.
$sort = array();
// Fill the array with ascending/descending numbers.
for ($i = 0; $i < $rows; $i++) {
$sort[$i]['var1'] = $i + 1;
$sort[$i]['var2'] = $rows - $i;
}
// Display the sorted array.
print "Sorted:\n";
print_rows($sort);
// Here's where the important bit happens:
// Create two arrays, each containing a list of the
// array keys from the sorted array (one for each column).
$var1 = array_keys($sort);
$var2 = array_keys($sort);
// Shuffle each list or array keys (one for each column).
shuffle($var1);
shuffle($var2);
// Create an empty array to hold shuffled values.
$shuffle = array();
// For every row in the list of shuffled keys, get
// the matching value from the sorted array, and
// place it in the shuffled array.
for ($i = 0; $i < $rows; $i++) {
$shuffle[$i]['var1'] = $sort[$var1[$i]]['var1'];
$shuffle[$i]['var2'] = $sort[$var2[$i]]['var2'];
}
// Display the shuffled array.
print "\nShuffled:\n";
print_rows($shuffle);
function print_rows($array) {
print "Row | Var 1 | Var2\n";
print "------------------\n";
foreach ($array as $key=>$row) {
printf("%3d | %5d | %4d\n", $key, $row['var1'], $row['var2']);
}
}
?>
Here's the output:
Sorted:
Row | Var 1 | Var2
------------------
0 | 1 | 20
1 | 2 | 19
2 | 3 | 18
3 | 4 | 17
4 | 5 | 16
5 | 6 | 15
6 | 7 | 14
7 | 8 | 13
8 | 9 | 12
9 | 10 | 11
10 | 11 | 10
11 | 12 | 9
12 | 13 | 8
13 | 14 | 7
14 | 15 | 6
15 | 16 | 5
16 | 17 | 4
17 | 18 | 3
18 | 19 | 2
19 | 20 | 1
Shuffled:
Row | Var 1 | Var2
------------------
0 | 8 | 2
1 | 19 | 12
2 | 14 | 5
3 | 16 | 17
4 | 2 | 8
5 | 11 | 4
6 | 7 | 11
7 | 9 | 10
8 | 12 | 1
9 | 5 | 9
10 | 13 | 20
11 | 10 | 6
12 | 17 | 19
13 | 18 | 18
14 | 4 | 14
15 | 20 | 7
16 | 3 | 16
17 | 15 | 15
18 | 6 | 3
19 | 1 | 13
The code is a bit rough and ready. I'm sure there are a number of ways in which it could be improved. For example, you could change it so the it is able to handle a variable number of columns. However, the basic idea is there.
Edit:
Here's a tidied up version of the code, which will handle a variable number of columns:
// Here's where the important bit happens:
// Create an empty array to hold shuffled values.
$shuffle = array();
// Get the name of each column (key) in the array.
foreach (array_keys($sort[0]) as $col) {
// Create an array of keys containing a list of the
// array keys from the sorted array.
$keys = array_keys($sort);
// Shuffle each list or array keys.
shuffle($keys);
// For every row in the list of shuffled keys, get
// the matching value from the sorted array, and
// place it in the shuffled array.
for ($i = 0; $i < $rows; $i++) {
$shuffle[$i][$col] = $sort[$keys[$i]][$col];
}
}
// Display the shuffled array.
print "\nShuffled:\n";
print_rows($shuffle);
You can do by 2 SQL statments:
SELECT Sort.Variable1 FROM Sort ORDER BY RAND(), Variable1 LIMIT 0 , 30
SELECT Sort.Variable2 FROM Sort ORDER BY RAND(), Variable2 LIMIT 0 , 30
if you need random in PHP array use: [array_rand][1]
<?php
// load all table values in array i just set them
$input = array("Neo", "Morpheus", "Trinity", "Cypher", "Tank");
$rand_keys = array_rand($input, 2);
echo $input[$rand_keys[0]] . "\n";
echo $input[$rand_keys[1]] . "\n";
?>
精彩评论