views:

76

answers:

3

Hello. 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');
        $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>';
            }
+2  A: 

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
Mark Byers
I'm sorry to ask this but if i know how to join tables, I have no ideas of how to join such results together. Could you give me a hand on this please ?
Coronier
@Coronier: Do you know about subselects? You need to emulate ROW_NUMBER in each subselect. http://stackoverflow.com/questions/1895110/row-number-in-mysql/1895127#1895127 then `JOIN t1.rank = t2.rank`
Mark Byers
This would result in the data being completely ordered, and only rows with duplicates in both Variable1 and Variable2 would be randomized between each other. Doesn't seem to be what the OP is looking for...
Joseph Mastey
@Joseph Mastey: The first bit was just explaining the syntax error - I have now deleted that part to avoid confusion. Did you see the second suggestion I made in my answer? I have now updated my answer to post the actual SQL required so you can try running it for yourself and let me know if you think it still doesn't work.
Mark Byers
A: 

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";
?>
Liutas
A: 

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);
Mike
That's totally what I was looking for. I can't thank you enough, I can now continue coding without an headache. Thanks for your complete and patient explanation.
Coronier
No problem. See the edit for an updated version.
Mike