PHP Total a multidimensional array - php

I have the following mysql query:
SELECT sub_nine, sum(sub.sub_low_nett) AS points, sub_pid FROM
(SELECT c.cn_nine as sub_nine, min(rh.rh_nett) AS sub_low_nett, p.id AS sub_pid
FROM round r, round_hole rh, player p, course_nine c, course_hole ch
WHERE r.r_id = rh.rh_rid
AND p.id = r.r_pid
AND c.cn_nine = r.r_nine
AND ch.ch_nine = c.cn_nine
AND rh.rh_hid = ch.ch_no
GROUP BY p.id, c.cn_nine, ch.ch_no
) AS sub
GROUP BY sub_pid, sub_nine
ORDER BY sub_pid
Which returns the following result:
|sub_nine|points|sub_pid
| 1 | 2 | 1
| 2 | 17 | 1
| 3 | NULL | 1
| 1 | NULL | 2
| 2 | NULL | 2
| 3 | NULL | 2
| 1 | NULL | 3
| 2 | 26 | 3
| 3 | 4 | 3
| 1 | 26 | 5
| 2 | 36 | 5
The result set has been looped into a multi-dimensional array, using the fetch_assoc() function.
I need to display each of the points totals per player as well as the total of those points (distinctly / uniquely) for each player in a table
I think I need to loop through the initial multi-dimensional array, and probably place into a new array that has been pivoted around the columns rather than rows, but stuck as to how to do this.
The initial query is sorted by pid, so I know that as you loop through the array, the rows can be cumulatively totaled.
I also need the final array to be sorted by the new total value per player as well.
pid | score1 | score2| score3 | total
the data structure is laid out here:
Gold DB ERD Diagram

Related

Is there a way to get unique rows for same value

Hello and sorry if this questions isn't good formatted, here's my problem:
for simplicity let's say i have a table with products
-----------------------
| id| age |price|name|
----------------------|
| 0 | 0 | 50 | x |
| 1 | 1 | 51 | x |
| 2 | 2 | 52 | x |
| 3 | 3 | 53 | x |
| 4 | 4 | 54 | x |
| 5 | 5 | 55 | x |
| 6 | 6 | 56 | x |
| 7 | 7 | 57 | x |
| 8 | 8 | 58 | x |
-----------------------
I want to get the price for all products of age 0 and 1 with
select price from products where name='x' and(age=0 or age=1)
and it works returning two rows but when the age is the same logically it returns one row and that's my problem how to get it to return again all the rows i want or if something other is wrong with my logic, thank you in advance
One way to achieve this is to build a derived table of the ages that you want to query against and then JOIN that to the products table. Note that you need to use UNION ALL in the derived table to maintain duplicates. Additional values can be searched by adding another UNION ALL SELECT n to the derived table for each value:
SELECT p.price
FROM (SELECT 0 AS age
UNION ALL
SELECT 0) ages
JOIN products p ON p.age = ages.age
WHERE p.name = 'x'
Output:
price
50
50
Demo on dbfiddle

MySQL and PHP: Getting a SUM from a row in column A based on a DATE from column A joined by an ID in column B?

So, as the title says, I think I want to get the SUM of a row in column A (Meta Value) based on matching DATEs in column A (Meta Value) joined from IDs in column B (Item ID).
Essentially, I want to look for a specific date 2017-05-05 in Meta Value. Then, when a date is a match, find the Item ID. In the example below, this would be 2 and 3. Then, get the SUM of the Field ID (11) for both Item ID 2 and Item ID 3 and return the SUM to a variable in PHP.
Here is what my data looks like:
+-----------+------------+------------+
| Meta Value| Field ID | Item ID |
+-----------+------------+------------+
| John | 8 | 1 |
|john#e.com | 10 | 1 |
| 2 | 11 | 1 |
|2016-11-20 | 12 | 1 |
| Mary | 8 | 2 |
|mary#e.com | 10 | 2 |
| **5** | 11 | 2 |
|2017-05-05 | 12 | 2 |
| Mike | 8 | 3 |
|mike#e.com | 10 | 3 |
| **2** | 11 | 3 |
|2017-05-05 | 12 | 3 |
+-----------+------------+------------+
I am after the SUM of 7 from Mike and Mary.
My current wordpress php call looks like this (but only gets me row count):
$bookings = $wpdb->get_var("SELECT COUNT(*) FROM wp_frm_item_metas WHERE field_id=12 AND meta_value='$select_date'");
Any help is appreciated!
seems you need sum on a self join
select sum(a.field_id)
from wp_frm_item_metas a
inner join wp_frm_item_metas b on b.item_id = a.item_id
and b.meta_value = '$select_date'
but if you need the sum for meta_value (11) you should
select sum(a.meta_vale)
from wp_frm_item_metas a
inner join wp_frm_item_metas b on b.item_id = a.item_id
and b.meta_value = '$select_date'
and a.filed_id =11

generate report grouped by day and department mysql

I have following table.
---+---------------+-------------+--------+
id | department_id | created | amount |
---+---------------+-------------+--------+
1 | 0 | 2016-05-05 | 500 |
2 | 2 | 2016-05-05 | 100 |
3 | 1 | 2016-05-05 | 160 |
4 | 2 | 2016-05-05 | 260 |
5 | 1 | 2016-05-04 | 100 |
6 | 0 | 2016-05-04 | 150 |
7 | 1 | 2016-05-04 | 160 |
8 | 2 | 2016-05-04 | 160 |
---+---------------+-------------+--------+
I want to generate report to show how much collection is there on particular day in particular department & need to show like below table:
Date | 0 | 1 | 2 |
2016-05-05 | 500 | 160 | 360 |
2016-05-04 | 150 | 260 | 160 |
I am using cakephp. If I use GROUP BY created it works and if I use GROUP BY department_id it works. But I need both GROUP BY to generate the required report.
I also tried generating the from to date array using this. and then tried running GROUP BY created on each date using following CakePHP query:
//$ar = date array
foreach ($ar as $k) {
$this->Transaction->find('all',array('conditions'=>array('Transaction.created'=>$k),'fields'=>array('SUM(Transaction.amount) AS s','Transaction.department_id'),'group'=>array('Transaction.department_id')));
}
But it seems like slow solution to me if date range is long. Is there any best way to do it in single query.
Please help me sorting this problem.
Variations of this question are asked and answered endlessly. A typical solution goes something like this...
SELECT created date
, SUM(CASE WHEN department_id = 0 THEN amount END) dept0
, SUM(CASE WHEN department_id = 1 THEN amount END) dept1
, SUM(CASE WHEN department_id = 2 THEN amount END) dept2
FROM my_table
GROUP
BY date;
simple group by two columns department_id and created - and sum(amount) function to calculate total for each group.
$report_rows = $this->{{Model_NAME}}->find('all', array(
'fields' => array('department_id', 'created', 'sum(amount)'),
'group' => 'department_id, created'
));
and then you can show this report on view
$dates = Set::extract('/{{Model_NAME}}/created', $report_rows);
$departments = Set::extract('/{{Model_NAME}}/department_id', $report_rows);
Now you can make dates in columns and departments as row title. Hope this help, it's not complied, may contain some bugs but logic will work well.

MySQL MIN() limit by column

I have a MySQL table that is formatted as follows:
group_clue:
---------------------------------------------------
| id | group_id | clue_id | completed | run_order |
---------------------------------------------------
| 1 | 1 | 2 | 1 | 1 |
| 2 | 1 | 6 | 1 | 2 |
| 3 | 1 | 4 | 1 | 3 |
| 4 | 1 | 3 | 0 | 4 |
| 5 | 1 | 1 | 0 | 5 |
| 6 | 1 | 5 | 0 | 6 |
| 7 | 2 | 9 | 1 | 1 |
| 8 | 2 | 2 | 0 | 2 |
...
---------------------------------------------------
The data above in the group_clue is constructed such that each group_id has every clue_id at some run_order (ranging from 1 to the number of clue_ids and not repeating for a particular group).
First Question
I want to create a table showing the first clue_id for each group_id where completed = 0 when ordered by run_order (aliased as current_clue). Using the above example, this would give:
---------------------------
| group_id | current_clue |
---------------------------
| 1 | 3 |
| 2 | 2 |
---------------------------
My preliminary attempt is:
SELECT group_id, MIN(clue_id) as current_clue
FROM group_clue
WHERE completed = 0
GROUP BY group_id
However, this returns the same clue_id for each group_id.
Second Question
From the data in the first question, I would like to compose a final table where I GROUP_CONCAT() these results so that it contains every current_clue and each group_id that contains that current_clue. I would also like it ordered from those clues with the most group_ids to those with the fewest. An example resulting table is:
--------------------
| clue | group_ids |
--------------------
| 3 | 1,5,4,3 |
| 2 | 2,6 |
--------------------
I cannot figure out the ordering. My preliminary attempt is:
SELECT clue_id, GROUP_CONCAT(group_id)
FROM [resulting_table]
GROUP BY clue_id
ORDER BY [something]
Any help is appreciated: what queries would fit this scenario?
The first part of your question can be solved this way (it expects that run_order is unique per group):
SELECT t1.group_id,
t1.clue_id AS current_clue
FROM group_clue t1
INNER JOIN (SELECT group_id,
MIN(run_order) as run_order
FROM group_clue
WHERE completed = 0
GROUP BY group_id) t2 USING (group_id, run_order)
The logic of this query is pretty simple:
The inner query selects the pairs of group_id and the corresponding minimal value of run_order which has the completed = 0.
After that we join the original table to this set of pairs so that we could select the corresponding clue_id additionally.
You can sort by number of elements per group using
ORDER BY COUNT(*) DESC

Merge Rows AND/OR Columns into one field in a GROUP BY

My SQL table looks like
+-----+------------+--------------+--------------+-----------+------------+-----------+
| rid | ship_to_id | product_code | product_name | first_row | second_row | third_row |
+-----+------------+--------------+--------------+-----------+------------+-----------+
| 1 | 555 | A | Crystal | 1 | 2 | 3 |
| 1 | 555 | A | Crystal | 4 | 5 | 6 |
| 2 | 333 | B | Diamond | first | second | third |
| 2 | 333 | A | Crystal | ROW 1 | ROW 2 | ROW 3 |
| 2 | 333 | A | Crystal | ROW 4 | ROW 5 | ROW 6 |
+-----+------------+--------------+--------------+-----------+------------+-----------+
And I am trying to get following results
+-----+------------+--------------+-------------------------------------+
| rid | ship_to_id | product_name | data |
+-----+------------+--------------+-------------------------------------+
| 1 | 555 | Crystal | 1 2 3 4 5 6 |
| 2 | 333 | Diamond | first second third |
| 2 | 333 | Crystal | ROW 1 ROW 2 ROW 3 ROW 4 ROW 5 ROW 6 |
+-----+------------+--------------+-------------------------------------+
Can someone please tell me what is wrong with my code. Thanks
$query = mysql_query("SELECT * FROM mytable group by rid, ship_to_id, product_code, product_name");
while($row = mysql_fetch_array($query)) {
echo "$row[rid] $row[ship_to_id] $row[product_code] $row[product_name] $row[first_row] $row[second_row] $row[third_row] <br>";
}
You're forgetting product_code sometimes, I guess.
This probably is bad database design. You should learn about Database normalization and related techniques.
Third, SQL normally produces the same number of columns for every result record, so the best result you could have has rows like 1, 555, "A", "Crystal", "1 4 2 5 3 6" (notice these are 5 values). But I cannot think of a concatenation method that would produce the numbers in the 1 2 3 4 5 6 order. Depending on the better form of your database-schema-to-be, this might be something easier done in PHP than SQL.
If you're still up to concatenating all values into a single cell (as in the newly formatted example output), the you should try something along these lines:
SELECT
rid, ship_to_id, product_code, product_name,
GROUP_CONCAT(CONCAT(first_row,'#',second_row,'#',third_row) SEPARATOR '~') AS data
FROM tablename
GROUP BY rid, ship_to_id, product_code, product_name;
Notice that the values of first_row etc. are separated by a '#' and the values from distinct records by a '~' sign. You can find more options in the documentation of MySQL's GROUP_CONCAT().
you can try something like
select rid,ship_to_id,product_name,
GROUP_CONCAT(CONCAT(first_row,' ',second_row,' ',third_row) as new_val
from mytable
group by rid,ship_to_id,product_name;
As you group by the first 4 columns and use no aggregation function on the remaining ones, data will be lost when multiple record have the same values in the columns grouped by.
So basically the result will be like the following:
+-----+------------+--------------+------------------------------------+
| rid | ship_to_id | product_name | first_row | second_row | thrid_row |
+-----+------------+--------------+------------------------------------+
| 1 | 555 | Crystal | 1 | 2 | 3 |
| 2 | 333 | Diamond | first | second | third |
| 2 | 333 | Crystal | ROW 1 | ROW 2 | ROW 3 |
+-----+------------+--------------+------------------------------------+
That's what group by means. To keep the data of the fields containing varying data, you must use an aggregation function on them, like GROUP_CONCAT. Example:
SELECT rid, ship_to_id, product_code, product_name, GROUP_CONCAT(first_row), GROUP_CONCAT(second_row), GROUP_CONCAT(third_row)
FROM mytable
GROUP BY rid, ship_to_id, product_code, product_name
This will concatenate the values of the corresponding record like this:
+-----+------------+--------------+------------------------------------------+
| rid | ship_to_id | product_name | first_row | second_row | thrid_row |
+-----+------------+--------------+------------------------------------------+
| 1 | 555 | Crystal | 1 4 | 2 5 | 3 6 |
| 2 | 333 | Diamond | first | second | third |
| 2 | 333 | Crystal | ROW 1 ROW 4 | ROW 2 ROW 5 | ROW 3 ROW 6 |
+-----+------------+--------------+------------------------------------------+
However, your approach with GROUP BY is probably not be the best for this case. It would worth to think about to just order by the rid, ship_to_id, product_code, product_name columns, and then iterate through them in PHP with the given order and merge the corresponding rows there.
You may also have to reconsider you database design, as a query like this smells about a bad concept :)

Categories