mysql order by photo_id desc and shuffle after - php

I want to select the most recent 12 rows from a table, but then shuffle the order.
So i cant use ORDER BY RAND() becouse that would just randomly pick some rows and not the most recent 12 rows.
I was thinking something like this, but it didnt work out as planned:
$artig_photos = mysql_query("
SELECT photo_id, photo_name
FROM `migo_artig_photos`
WHERE (
photo_deleted=0 AND photo_type=2
)
ORDER BY photo_id DESC
LIMIT 12;
");
while ($row = mysql_fetch_array($artig_photos)) {
$artig_shuffled[$row['photo_id']] = $row['photo_name'];
}
shuffle($artig_shuffled);
later when i do:
foreach ($artig_shuffled as $key => $value) {
}
i expected the key to be photo_id and the value to be photo_name with the correct relation between them, guess i was wrong.
Any tips about how to solve this problem? Maybe my approach isnt good at all.
Best of regards,
Alexander

You could put them all in an array in PHP, then randomize the order of that array with shuffle(), or make the query to select the most recent 12 a sub query, then randomize the results with the outer query. Just store the items with $items[] = $row;, then shuffle($items); and iterate over it. You wont get the $photo_id in $key, but it will still be in $item['photo_id']

PHP's shuffle() function removes any existing keys from your array:
Note: This function assigns new keys to the elements in array. It will remove any existing keys that may have been assigned, rather than just reordering the keys.
This function is best used with numerically indexed arrays. A quick approach would be to just write your own shuffle function that works on associative arrays. I found this one on a previous Stack Overflow post:
function shuffle_assoc($list) {
if (!is_array($list)) return $list;
$keys = array_keys($list);
shuffle($keys);
$random = array();
foreach ($keys as $key) {
$random[] = $list[$key];
}
return $random;
}
Link to the original:
PHP Random Shuffle Array Maintaining Key => Value

You could use a subquery:
SELECT * FROM (
SELECT `migo_artig_photos`.`photo_id`,
`migo_artig_photos`.`photo_name`
FROM `migo_artig_photos`
WHERE `migo_artig_photos`.`photo_deleted` = 0 AND
`migo_artig_photos`.`photo_type` = 2
ORDER BY photo_id DESC
LIMIT 12) `top_12_migo_artig_photos`
ORDER BY RAND();
Alternatively, you could do this:
// To shuffle:
while ( $row = mysql_fetch_array($artig_photos) )
{
$artig_shuffled[] = $row;
}
shuffle($artig_shuffled);
// To display:
foreach ( $artig_shuffled as $row )
{
echo $row['photo_id'];
echo $row['photo_name'];
}

Related

Why is array_unique not working in this situation

I have a column that contain integer values. I join all columns by doing
"SELECT GROUP_CONCAT(column) AS column"
Then I build an array doing
while ($row = $result->fetch_assoc()){
$employees[] = $row['column'];
}
print_r($employees) returns Array ( [0] => 1,2,3,4,68,25,1 )
So I want to remove the duplicate 1 and for that I use array_unique
print_r(array_unique($employees));
This still brings back Array ( [0] => 1,2,3,4,68,25,1 )
What am I doing wrong here
Solution at SQL side:
SELECT GROUP_CONCAT(DISTINCT column) AS column
if you want an ordered list:
SELECT DISTINCT column ORDER BY Column
and then store all rows by
while(...) $employees[] = $row['column'];
The problem is that you are trying to use array_unique() on a string, which won't really do anything.
You can break this string into an array by using the explode() function.
$unique = array_unique(explode(',', $employees[0]);
Alternatively, you could just check inside your loop if a value has already been put into an array using in_array().
while ($row = $result->fetch_assoc()){
if(!in_array($row['column'], $employees)) {
$employees[] = $row['column'];
}
}
Just use the array_map function. And map all value with intdiv function
$employees = array_unique(array_map("intdiv", $employees));
print_r($employees);

Sorting an array in PHP vs fetching data from SQL

I am using the following php method to find the top 10 occuring elements in an array and then returning a new array with those 10 elements along with how many times they appear. This is fine for rather small arrays. But I get my data from a database and the arrays can easily be over 100000 in size. This causes this method to be extremely slow. The code is as follows:
function getTopTenSelects($array) {
$result = [];
for ($x = 0; $x <= 10; $x++) {
$count = countArray($array);
$mostOccuring = (key($count));
$arrayReturn[$x] = $mostOccuring;
array_push($result, [$mostOccuring,$count[$mostOccuring]]);
foreach ($array as $temp) {
if (($key = array_search($mostOccuring, $array)) !== false) {
// Cuts the key from the array foreach time it appears so we can find the next most occuring value
unset($array[$key]);
}
}
}
return $result;
}
Now. I get my array through the following SQL query. $hashtag is a variable that contains a piece of string.
SELECT tag_names
FROM soc_stat
JOIN tags on soc_stat.insta_id = tags.insta_id
WHERE main_tag = $hashtag
Is there an efficient way of doing it in php, or is there a way to get what I need through an SQL query?
Of course you should retrieve only the data from the database that is really needed in order to have small data exchange. In your case the top 10 tag names:
SELECT tag_names, count(*)
FROM soc_stat
JOIN tags on soc_stat.insta_id = tags.insta_id
WHERE main_tag = $hashtag
group by tag_names
order by count(*) desc limit 10;

Can I set multiple Codeigniter Where criteria from an array?

I am trying to get data from a database that meets multiple criteria of an array.
The array is something like this:
Array ([21] => 1,[23] => 0,[19] => 1);
With the key being a Question ID and the values being either yes or no.
I need to find the movie where the value for question_id = 21 is 1, value for question_id = 23 is 0 and value for question_id = 19 is 1. The way I have them stored is like this:
So my first thought was get the data for each and then put them in a bigger array. If the movie shows up the same amount of times as the number of elements in the array, then I consider it a good match. But this seems inefficient. I would rather just find the movies that match the criteria.
Since there are movie_id records with the same value, is there a way to write something like this?:
foreach($array as $key=>$value){
$i++;
$this->db->where('question_id', $key);
$this->db->where('value', $value);
}
$this->db->from('movies_values');
$query = $this->db->get();
$res = $query->result();
array_push($main,$res);
The thought behind this is to create a loop of all the WHEREs. And then run the query using those where values. This doesn't seem to work, is there something else I can do?
How about using WHERE IN (array())?
From the CI User Guide:
$names = array('Frank', 'Todd', 'James');
$this->db->where_in('username', $names);
// Produces: WHERE username IN ('Frank', 'Todd', 'James')
Use the where_in method for lists:
$this->db->where_in('value', $array);
Try doing it like this.
$where = WHERE 1
foreach($array as $key=>$value){
$where .= " AND(question_id = $key AND value = $value)";
}
$this->db->where($where);
PS. What is the $i++ doing in your loop exactly?
I think this is the right way to go, you should take care to use "or" instead to use full "ands" that way would not return any row due to a logic problem (I mean question_id = 1 and value = 1 and question_id = 2 and value = 0 we're being inconsistent due to telling that we want question_id = 1 and question_id = 2 won't match nothing!, the same applies to "values").
$array = array(21 => 1,23 => 0,19 => 1);
$where = array();
foreach($array as $key => $value) {
$where[] = "(question_id=$key and value=$value)";
}
var_dump($where);
foreach ($where as $value) {
$this->db->or_where($value);
}
$q = $this->db->get('movies_values')->result();
var_dump($q);
echo $this->db->last_query();exit;
This can be done easily without loop:
$filter = array(21 => 1,23 => 0,19 => 1);
$values = implode(',',array_unique(array_values($filter))); // results into 0,1...
$keys = implode(',',array_unique(array_keys($filter))); // results into 19,21,23...
$result = $this->db
->query("select * from movies_values
where
question_id in(".$keys.")
and value in(".$values.")")
->result();
Happy coding ---> :)

i was wondering how to handle a MySQL request in php as an Object?

I was wondering how I can handle a mysql request in php precisely as an object.
Ex:
//supposing...
$beginning=$_GET['start'];//value equal to 3
$ending=$_GET['end'];//value equal to 17
$conn=new mysqli("localhost","user","password","databasename");
$query=$conn->query("select name, favoriteFood, weight, from tablename");
1- Supposing that tablename has 23 rows, how to printing only 14 rows, beginning for example by 3rd row and ending in 17th row, as following?
Ex:
//supposing... It, I guess, should result in error but is a sketch of my ideia
for($i=$beginning,$colsCol=$query->fetch_array(MYSQLI_ASSOC); $i<$ending; $i++)
printf("%s %s %s<\br>",$colsCol['name'][$i],$colsCol['favoriteFood'][$i],$colsCol['weight'][$i]);
2 - And later, how to order the resulted rows with $query variable?
P.S.: I know that to get results ordered, I could user order by columname, but in this case I would like to order the resulted rows after query been done.
If you want to sort later, after the query's done, then you'd need to store the results in a PHP data structure and do the sorting there. Or re-run the query with new sorting options.
As for fetching only certain rows, it'd be far more efficient to retrieve only the rows you want. Otherwise (for large result sets) you're forcing a lot of data to be pulled off disk, sent over the wire, etc... only to get thrown away. Rather wasteful.
However, if you insist on doing things this way:
$row = 0; $data = array();
while($row = $query->fetch_array(MYSQLI_ASSOC)) {
$row++;
if (($row < 3) || ($row > 17)) {
continue;
}
$data[] = $row;
}
for 2D array you can use it.
function asort2d($records, $field, $reverse=false) {
// Sort an array of arrays with text keys, like a 2d array from a table query:
$hash = array();
foreach($records as $key => $record) {
$hash[$record[$field].$key] = $record;
}
($reverse)? krsort($hash) : ksort($hash);
$records = array();
foreach($hash as $record) {
$records []= $record;
}
return $records;
} // end function asort2d
Use SQL for SQL-tasks:
"how to printing only 14 rows, begging for example by 3rd row and ending in 17th row"
$stmt = $database->prepare('SELECT `name`, `favoriteFood`, `weight` FROM `tablename` LIMIT :from, :count');
$stmt->bindValue(':from', (int)$_GET['start'] - 1);
$stmt->bindValue(':count', (int)$_GET['end'] - (int)$_GET['start']);

PHP Sorting associative-array by other array

I need to sort an associative-array in the exact order of the content of another array.
The Arrays are retrieve by 2 separate sql-requests (stated below). The requests could not be combined to only one request, so I have to sort the second array into the order of the first one.
These are the arrays:
#Array which contains the id's in needed order
$sorting_array = array(1,2,3,8,5,6,7,9,11,10...);
#Array which contains the values for the id's, but in order of "id" ASC
$array_to_sort = array(
array("id" => "1", "name" => "text1", "help" => "helptxt2");
array("id" => "2", "name" => "text2", "help" => "helptxt2");
);
The SQL-Queries:
SQL-Ouery for $sorting_array: (the db-field 'conf' is setup as "text", maybe this is my problem so that I have to first explode and implode the entries before I could use it for the next query.)
$result = sql_query("select conf from config where user='me'", $dbi);
$conf = sql_fetch_array($result, $dbi);
$temp = explode(',', $conf[0]);
$new = array($temp[0], $temp[1], $temp[2], $temp[3],$temp[4],
$temp[5], $temp[6], $temp[7], $temp[8], $temp[9],
$temp[10], ...);#Array has max 30 entries, so I count them down here
$sorting_array = implode(',', $new);
SQL-Ouery for $array_to_sort:
$result = sql_query("SELECT id, name, helptxt
FROM table
WHERE id IN ($sorting_array)
AND language='english'");
while ($array_to_sort[] = mysql_fetch_array ($result, MYSQL_ASSOC)) {}
array_pop($array_to_sort);#deleting the last null entry
I could access $array_to_sort as follows to see the content one by one:
(if the lines below don't match the array above, than I mixed it up. However, the lines below is what brings the content)
echo $array_to_sort[0]["id"];
echo $array_to_sort[0]["name"];
echo $array_to_sort[0]["helptxt"];
But it is sorted by "id" ASC, but I need exactly the sorting as in $sorting_array.
I tried some things with:
while(list(,$array_to_sort) = each($sorting_array)){
$i++;
echo $array_to_sort . "<br>";
}
which only brings the Id's in the correct order, but not the content. Now I'm a bit confused, as I tried so many things, but all ended up in giving me the same results.
Maybe the sql-query could be done in one step, but I didn't brought it to work.
All results to my searches just showed how to sort ASC or DESC, but not what I want.
Furthermore I must confess that I'm relative new to PHP and MySQL.
Hopefully some one of you all could bring me back on track.
Many thanks in advance.
To fetch your results:
$result = mysql_query("SELECT id, name, helptxt
FROM table
WHERE id IN ($sorting_array)
AND language='english'");
$array_to_sort = array();
while ( ($row = mysql_fetch_assoc($result)) !== false ) {
// associate the row array with its id
$array_to_sort[ $row[ "id" ] ] = $row;
}
To display them in order of $sorting_array:
foreach ( $sorting_array as $id ) {
// replace the print_r with your display code here
print_r( $array_to_sort[ $id ] );
}
And a bonus tip for the code fetching $sorting_array:
$result = mysql_query("select conf from config where user='me'", $dbi);
$conf = mysql_fetch_array($result, $dbi);
$temp = explode(',', $conf[0]);
// limit to 30 ids
$new = array();
// no need to do this manually, use a loop
for ( $i = 0; $i < 30; ++$i )
$new[] = $temp[ 0 ];
$sorting_array = implode(',', $new);
Its a little hard to tell because there is a lot going on here, in the future you'll probably get better/more responses if you ask several simple questions and figure out yourself how to make the answers fit together.
Your best bet long term is going to be to restructure your SQL tablessuch that you can combine these query together. You can do what you're asking in PHP, but it's going to be slower than doing it in MySQL and much more complicated.
To do what you're asking (pretty slow in PHP):
$sorted = array();
foreach ( $sorting_array as $id )
{
foreach ( $array_to_sort as $values )
{
if ( $values['id'] == $id )
{
$sorted[] = $values;
break;
}
}
}
what I tend to do in such a situation is first to rearrange the array with the data. so the keys represent ids
In your case:
$array_to_sort_ids = array();
foreach ($array_to_sor as $item)
{
$array_to_sort_ids[$item['id']] = $item;
}
Then sorting is as simple as:
$array_sorted = array();
foreach ($sorting_array as $id)
{
$array_sorted[] = $array_to_sort_ids[$id];
}
This solution is quite efficient, since you only have 2 foreach loops.
EDIT!!!
As I couldn't edit my question anymore, I just like to state my solution this way:
The tip to rethink my database was what brought me to some testings and then I found the solution, with the following query:
$result = sql_query("SELECT id, name, helptxt
FROM table
WHERE id IN ($sorting_array)
AND language='english'
ORDER BY FIELD(id,$sorting_array)");
while ($array_to_sort[] = mysql_fetch_array ($result, MYSQL_ASSOC)) {}
array_pop($array_to_sort);#deleting the last null entry
Just the line:
ORDER BY FIELD(id,$sorting_array)
will do the trick. It orders the results the way you want, even if this means 1,4,2,3,9,7,...
Sometimes it's so easy, when you know where to look.
Thanks again!!!

Categories