A single MySQL query for select top 3 within groupon-by? - mysql

I have a table deals, and columns are name, amount, division, category.
For each division category combination, I want to find top 3 entries with max amount.
The final result should be in the format: name, division, category.

$db = new PDO($hostname,$username,$password);
$query = 'Select name, division, category
From deals Where division = :division And category = :category
ORDER BY amount DESC Limit 3';
then create arrays of all your divisions and categories and loop them:
$top3s = array();
foreach($divisionArray as $division)
{
foreach($categoryArray as $category)
{
$statement = $db->prepare($query);
$statement->bindValue(':division', $division);
$statement->bindValue(':category', $category);
$statement->execute();
$top3 = $statement->fetch(PDO::FETCH_ASSOC);
$statement->closeCursor();
array_push($top3s, $top3);
}
}
print_r $top3s;

Related

Mysql PDO (Getting total from all colums) [duplicate]

I'm new to php and I've searched for the past hour and read all the documentation I could find and nothing is helping. I have a table that has a bunch of rows of data. I'm trying to pick one column from the whole table and add them all together. Here is what I got. All this tells me is how many rows there are that match my query, not the total sum of column I want. Any help is appreciated.
$res1 = $db->prepare('SELECT sum(distance) FROM trip_logs WHERE user_id = '. $user_id .' AND status = "2"');
$res1->execute();
$sum_miles = 0;
while($row1 = $res1->fetch(PDO::FETCH_ASSOC)) {
$sum_miles += $row1['distance'];
}
echo $sum_miles;
You're only returning one row in this instance. Modify your summed column to have an alias:
SELECT SUM(distance) AS totDistance FROM trip_logs ....
Now you can can fetch the row -
$row = $res1->fetch(PDO::FETCH_ASSOC);
echo $row['totDistance'];
No need to loop.
You can use SUM() without explicitely grouping your rows because if you use a group function in a statement containing no GROUP BY clause, it is equivalent to grouping on all rows.
If however you want to use the SUM() function for something slightly more complicated you have to group your rows so that the sum can operate on what you want.
If you want to get multiple sums in a single statement, for example to get the distance for all users at once, you need to group the rows explicitely:
$res1 = $db->prepare("
SELECT
SUM(distance) AS distance,
user_id
FROM trip_logs WHERE status = '2'
GROUP BY user_id
");
$res1->execute();
while ($row = $res1->fetch(PDO::FETCH_ASSOC))
{
echo "user $row[user_id] has runned $row[distance] km.\n";
}
This will return the sum of distances by user, not for all users at once.
Try this if you are using a Class :
class Sample_class{
private $db;
public function __construct($database) {
$this->db = $database;
}
public function GetDistant($user_id,$status) {
$query = $this->db->prepare("SELECT sum(distance) FROM trip_logs WHERE user_id =? AND status =?");
$query->bindValue(1, $user_id);
$query->bindValue(2, $status);
try{ $query->execute();
$rows = $query->fetch();
return $rows[0];
} catch (PDOException $e){die($e->getMessage());}
}
}
$dist = new Sample_class($db);
$user_id = 10;
$status = 2;
echo $dist->GetDistant($user_id,$status);

How to retrieve every combination of numbers from 2 columns

I'm trying to find a way to retrieve every combination of values from two columns in a table, where each combination matches a value in a third column.
Say part of the table looks like this:
products_id options_id options_values_id
1487 2 1
1487 2 61
1487 3 60
1487 5 52
My desired output, when working with products_id 1487, would be the following two strings:
2-1, 3-60, 5-52
2-61, 3-60, 5-52
I've got the impression that those strings would need to be assembled recursively, but I ran into trouble trying it that way because not every products_id has the same options_ids, or the same number of them.
Edited to add: I've tried variations of a couple of the solutions below, but to no avail. I think I should have been more descriptive.
I'm trying to have it retrieve every combination of unique options_id and its corresponding options_values_id. (In other words, not every single possible combination of numbers from those two columns.) Options_id represents product options like "color" and "size," and options_values_id represents choices of those options, like "red" or "small." So I'm trying to come up with every possible combination of options for a given products_id. In the example above, there are two possible option combinations for that item-- "2-1, 3-60, 5-52" and "2-61, 3-60, 5-52".
Join the table against itself for each distinct option.
Do a select first to retrieve the number of options.
$tables = array();
$rs = mysql_query(
'SELECT DISTINCT options_id FROM table WHERE products_id = '.$id);
while ($row = mysql_fetch_row($rs)) {
$tables[$row['options_id']] =
'SELECT options_values_id FROM table WHERE products_id = '.$id.
' AND options_id = '.$row['options_id'];
}
mysql_free_result($rs);
Then, for each option, join it in as a separate table in your query. Do not include any joining clauses comparing values, just join every record against every other record.
$sql = 'SELECT ';
$count = 0;
foreach ($tables AS $id => $query) {
if ($count++) $sql .= ', ;
$sql .= 'table_'.$id.'.options_values_id AS value_'.$id;
}
$sql .= ' FROM ';
$count = 0;
foreach ($tables AS $id => $query) {
if ($count++) $sql .= ', ';
$sql .= '('.$query.') AS table_'.$id;
}
Finally, execute that query. Each row will contain one column per options_id. There will be one row per unique combination of values.
or for a mixed, php/sql approach, try using that SQL query:
SELECT products_id, options_id, options_values_id WHERE products_id = '$var_with_product_id';
fetch the results into an array, say $results:
$pairs = array();
foreach($results as $result) {
// build array with pairs (array_push to avoid overwriting)
array_push($pairs, array( $result['options_id'] => $result['options_values_id'];
}
// a bit extra complication, as array_push adds e.g. [0] => array( options_id => options_values_id ) :)
$pairs = array_values($pairs);
// check for double options_id
$found_double_options_id = false;
do {
// check for duplicates... use a lot of array functions
} while (count($pairs) && $found_double_options_id);
"Every combination" is the Cartesian product:
SELECT DISTINCT e1.options_id, e2.options_values_id
FROM Entity e1, Entity e2
WHERE e1.products_id = 1487 AND e2.products_id=1487

How to refer to one table when two tables have been used in a MySQL query?

Up until now I have just been using one table in a MySQL query, but now I am using two tables in a query to return only users' favourites, i.e.:
$query1="SELECT tracks.id, favourites.track FROM tracks, favourites WHERE tracks.id = favourites.track";
$result=mysql_query($query1) or die(mysql_error());
I am wondering how then I would refer to columns in rows in just the tracks table to construct variables from this query. Previously I used:
while ($row = mysql_fetch_array($result)) {
$title = $row['title'];
...etc
}
But obviously this needs adapting to refer to just the rows in the tracks table, but how do I do this?
You can do the same using:
$query1="SELECT T.id as Tid, F.track , T.title as Title FROM tracks T inner join favourites F ON T.id = F.track";
$result = mysql_query($query1);
while ($row = mysql_fetch_object($result))
{
$title = $row->Title;
$tid = $row->Tid;
/*...etc...*/
}

Order by clause in MySQL is not working inside a foreach loop

I'm trying to get the profiles names which are assigned to a specific subcategory
with id=9. When I run the code below, I get the profiles that I want but for some
reason the ORDER BY clause in the foreach loop doesn't sort them by their name
alphabetically. Instead they are ordered in the same way they are ordered inside the
'profiles' field in 'subcategories' table (the IDs for the profiles are comma separated).
For example if in subcategories['profiles'] I have ',5,1,2' the profiles names will be displayed
in the following order:
Profile with ID=5
Profile with ID=1
Profile with ID=2
I'm using the explode() function to get the ID for each profile inside the 'subcategory'
table and then use that ID to retrieve their information from the 'profile' table using
a query inside the foreach loop.
Am I missing anything here? Thanks for your help.
Here's my code:
<?php
$subcategories=mysql_query("select * from subcategories where id='9'");
while ($subcategories = mysql_fetch_array($subcategories))
{
$profiles = $subcategories['profiles'];
$profiles = explode(',', $profiles);
foreach ($profiles as $p)
{
$all_places = mysql_query("select * from profile where id='$p' and active='1' order by name asc");
while ($profile = mysql_fetch_array($all_places))
{
echo $profile['name'];
}
}
}
?>
Well the reason why your results do not order by name is because you are retrieving every profile with a new SQL query in your foreach loop for $profiles. So effectively in your scenario, you will end up with 3 SQL queries that returns 1 profile each. Hence, when the "order by" clause is declared, it orders by name within each query, which only contains 1 result each.
does using an IN statement work for you? Eg.
<?php
$subcategories=mysql_query("select * from subcategories where id='9'");
while ($subcategories = mysql_fetch_array($subcategories))
{
//i assume $subcategories['profiles'] are integers separated by comma as mentioned
$profiles = $subcategories['profiles'];
$all_places = mysql_query("select * from profile where id IN ($profiles) and active='1' order by name asc");
while ($profile = mysql_fetch_array($all_places))
{
echo $profile['name'];
}
}
?>

How to combine sql select queries for this situation?

i'm writing a chat app with php/mysql
i have 3 tables: user, room and room_participant with these structures:
user: id, username
room: id, title
room_participant: room_id, user_id
Now i want to get list of all rooms along with list of all participants in each room.
Until now i just select all rooms from room table and iterate through all rooms and select users information out of each entry, which is very inefficient.
Is there any way to combine all these select into only 1 select query?
Not certain about this without testing, but give it a try:
SELECT
room.*,
user.*
FROM room
JOIN room_participant ON room_id = room_participant.id
JOIN user ON room_participant.user_id = user.id
ORDER BY room.id
To deduplicate rooms, use GROUP_CONCAT()
UPDATE GROUP_CONCAT() modified to return id|username
SELECT
room.id, room.name
GROUP_CONCAT(CONCAT(user.id,'|',user.username)) AS userlist
FROM room
JOIN room_participant ON room_id = room_participant.id
JOIN user ON room_participant.user_id = user.id
GROUP BY room.id, room.name
ORDER BY room.id
With the userlist generated by GROUP_CONCAT as id|name,id|name,id|name you can use PHP explode() to separate them.
// Split the list on the commas
$users = explode(",", $userlist);
$final_users = array();
// Then split each on the `|`
foreach ($users as $user) {
$split_user = explode("|", $user);
// Append each as a new associative array to $final_users
$final_users[] = array('id' => $split_user[0], 'username' => $split_user[1]);
}
// Now you have an array of users as id, username
var_dump($final_users);
You may wish to do two queries, and then match things up in whatever is using MySQL, e.g. PHP.
These two:
SELECT id, title
FROM room;
SELECT rp.room_id, rp.user_id, u.username
FROM room_participant AS rp
INNER JOIN user as u ON rp.user_id = u.id;
Or these two:
SELECT id, username
FROM user;
SELECT rp.room_id, rp.user_id, r.title
FROM room_participant AS rp
INNER JOIN room as r ON rp.user_id = r.id;
Which two queries make sense depends on what you're doing with the info really.
You could go a step further and select all three separately:
SELECT *
FROM room;
SELECT *
FROM user;
SELECT *
FROM room_participant;
Note: It's probably better to state the columns, rather than using '*', just in case in the future new columns are added to the table that you're not really interested in for these queries.
Obviously, you'd then have to match everything up in whatever is using MySQL, e.g. PHP. You could create a list of rooms and users from the selected info, and then match them up with something like:
// Use MySQL to populate $roomList from database, then do...
foreach ($roomList as $room)
{
$id = $room['id'];
$title = $room['title'];
$this->roomList[$id] = new Room($id, $title);
}
// Use MySQL to populate $userList from database, then do...
foreach ($userList as $user)
{
$id = $user['id'];
$username = $user['username'];
$this->userList[$id] = new User($id, $username);
}
// Use MySQL to populate $roomParticipantList from database, then do...
foreach ($roomParticipantList as $roomParticipant)
{
$room = $this->roomList[$roomParticipant['room_id']];
$user = $this->userList[$roomParticipant['user_id']];
// You could do one/both of these, depending on requirements.
$room->enterUser($user);
$user->joinRoom($room);
}