PHP: foreach loop by id and month and add values - php

I've been trying to solve this issue I'm currently having. We have a table with id, productid, userid, count and downloaddate. Something like below to understand the structure and what the results look like.
+----+-----------+--------+-------+---------------+
| id | productid | userid | count | downloaddate |
+----+-----------+--------+-------+---------------+
| 1 | 9 | 231 | 2 | October 2017 |
| 2 | 8 | 230 | 1 | October 2017 |
| 3 | 9 | 287 | 1 | October 2017 |
| 4 | 9 | 200 | 2 | November 2017 |
+----+-----------+--------+-------+---------------+
So what I want to loop is to get all the productid and return the total number of count for the given month which is recorded in the downloaddate column.
To return this:
+------------+-------+---------------+
| productid | count | downloaddate |
+------------+-------+---------------+
| 9 | 3 | October 2017 |
| 8 | 1 | October 2017 |
| 9 | 2 | November 2017 |
+------------+-------+---------------+
Is it possible to do this? I've tried this but it's returning the total count for the productid
$sum = array();
$emparray = array();
foreach ($downloads as $download){
$emparray[] = $download;
}
foreach ($emparray as $downloaded){
if (!isset($sum[$downloaded->id])) {
$sum[$downloaded->id]['count'] = $downloaded->count;
$sum[$downloaded->id]['downloaddate'] = $downloaded->downloaddate;
} else {
$sum[$downloaded->id]['count'] += $downloaded->count;
$sum[$downloaded->id]['downloaddate'] = $downloaded->downloaddate;
}
}
Any help will be appreciated!
EDIT
This is my sql query:
$downloads = $wpdb->get_results(
"
SELECT ast.*, dl.userid, dl.count, dl.downloaddate
FROM $lead_table as ast
JOIN $table_downloads as dl ON (dl.productid = ast.id)
"
);

You can get the result by one query grouping by productid and downloaddate (I hope that October2017 is a typo in the question)
SELECT productid, sum(count) as count, downloaddate
FROM your_table
GROUP BY productid, downloaddate
update. with your query it seems to be
SELECT ast.*, dl.userid, sum(dl.count) as count, dl.downloaddate
FROM $lead_table as ast
JOIN $table_downloads as dl
ON (dl.productid = ast.id)
GROUP BY dl.userid, dl.downloaddate

i think you should edit your sql Query into this :
SELECT productid, sum(count) as count, downloaddate FROM your_table GROUP BY downloaddate

You have to be able to tell which month is given in the downloaddate (can you build a timestamp ? Or something else that tells you that "October2017" is the same that "October 2017".
Once you got that, you "just" have to store your "sum" in a 2D array with something like that:
$sum = array();
foreach ($downloads as $download) {
// dateToTimeStamp: custom function who gives you the same number for October2017 or October 2017
$timestamp = dateToTimeStamp($downloaded->downloaddate);
if (!isset($sum[$timestamp])) {
$sum[$timestamp] = [];
}
if (!isset($sum[$timestamp][$downloaded->id])) {
$sum[$timestamp][$downloaded->id]['count'] = $downloaded->count;
$sum[$timestamp][$downloaded->id]['downloaddate'] = $downloaded->downloaddate;
continue 1;
}
$sum[$timestamp][$downloaded->id]['count'] += $downloaded->count;
$sum[$timestamp][$downloaded->id]['downloaddate'] = $downloaded->downloaddate;
}

you can easily use this query and extract the data from php and use it there
select productid,sum(count),downloaddate from tablename group by productid,downloaddate

Related

SQL query returns one row too few

SOLUTION: Make sure you don't 'use up' any $responses->fetch_assoc()s before the while loop.
I performed mysqli_fetch_array($responses);.
In php I have this sql query (simplified for your convenience, but the problem remains)
$sql = "SELECT id, content FROM responses ORDER BY RAND()";
$responses = $conn->query($sql);
where the responses table looks like this:
+----+----------+--------+------+
| id | content | userId | part |
+----+----------+--------+------+
| 4 | peewee | 31 | 1 |
| 5 | tallinn | 31 | 1 |
| 6 | dewey | 31 | 1 |
| 7 | stanford | 31 | 1 |
+----+----------+--------+------+
That doesn't format properly so all you need to know is that the id and content rows are different for each entry while the rest is the same for each.
The problem is, when I do a while loop on $responses like so:
while ($row = $responses->fetch_assoc()) {
$responseId = $row["id"];
$content = $row["content"];
echo " id: ".$responseId;
echo " content: ".$content;
}
I always get 1 record fewer than there are. In this case, since there are 4 rows, I would only see 3 echoed. However, it is not always the same 3, nor are they in the same order. If I remove the ORDER BY RAND() clause, then it is always the first record which is left out.
Thanks in advance
Cheers

How can I optimize query to run faster (Query inside a Query)

This query will take around 5 seconds to complete. I mean when I refresh or navigate to the page it will take 5 seconds to complete the browser loading and to display the total counts.
Here is what I want to achieve, FIRST is to get the MAX value of the systemID (ID) based on the empID.
But before the First query ends I made another query the will get the row where the empID has a JUMP value on the eStatus col.
This is to compare the year difference of the latest data startDate of the empID and to his previous JUMP endDate.
Here is my table
---|-------|-----------|------------|---------
ID | empID | startDate | endDate | eStatus
---|-------|-----------|------------|---------
1 | 10 | 2001-1-31 | 2001-12-31 |
2 | 10 | 2002-1-31 | 2002-12-31 |
3 | 22 | 2001-1-31 | 2001-12-31 |
4 | 10 | 2003-1-31 | 2003-12-31 | JUMP
5 | 10 | 2004-1-31 | 2004-12-31 |
6 | 22 | 2002-1-31 | 2002-12-31 | JUMP
7 | 10 | 2005-1-31 | 2005-12-31 |
8 | 22 | 2003-1-31 | 2003-12-31 |
9 | 22 | 2004-1-31 | 2004-12-31 |
10 | 10 | 2006-1-31 | 2006-12-31 | JUMP
11 | 10 | 2007-1-31 | 2007-12-31 |
12 | 10 | 2008-1-31 | 2008-12-31 |
13 | 10 | 2009-1-31 | 2009-12-31 | JUMP
14 | 10 | 2010-1-31 | 2010-12-31 |
15 | 10 | 2011-1-31 | 2011-12-31 |
the First query will get the max ID by group of empID.
---|-------|-----------|------------|---------
ID | empID | startDate | endDate | eStatus
---|-------|-----------|------------|---------
15 | 10 | 2011-1-31 | 2011-12-31 |
9 | 22 | 2004-1-31 | 2004-12-31 |
the Second query will get the empID row that has a JUMP data on the eStatus Col
---|-------|-----------|------------|---------
ID | empID | startDate | endDate | eStatus
---|-------|-----------|------------|---------
4 | 10 | 2003-1-31 | 2003-12-31 | JUMP
6 | 22 | 2002-1-31 | 2002-12-31 | JUMP
10 | 10 | 2006-1-31 | 2006-12-31 | JUMP
13 | 10 | 2009-1-31 | 2009-12-31 | JUMP
6 | 22 | 2002-1-31 | 2002-12-31 | JUMP
Now I can compute the date difference from startDate of 1st query and enddate of 2nd query. If it is greater than 2 the it will count to my final count.
THANK YOU SO MUCH IN ADVANCE and KEEP SAFE.
Here is my code:
<?php
$counterA= 0;
$counterB= 0;
$finalCount = 0;
$result = mysqli_query($con,"SELECT empID,endDate FROM tablerecord
WHERE ID IN (SELECT MAX(ID) FROM tablerecord GROUP BY empID)");
while ($row=mysqli_fetch_assoc($result )) {
$counterA++; //count how many result based on the above query
$emp_max = $row['empID']; //Get emp ID based on max ID
endDate_result = $row['endDate']; //Get endDate based on max ID
$resultPrevious=mysqli_query($con,"SELECT empID,startDate FROM tablerecord
WHERE empID = '$emp_max' AND eStatus = 'JUMP' ");
while ($rowPrevious=mysqli_fetch_assoc($resultPrevious)) {
$counterB++; //count how many result based on the above query
$dateA=date_create($rowPrevious['startDate']);
$dateB=date_create($endDate_result);
$diff2=date_diff($dateA,$dateB);
$numLenght = $diff2->y;
if ($numLenght > 2) {
$finalCount++;
}
}
}
echo $counterA;
echo "<br>";
echo $counterB;
echo "<br>";
echo $finalCount;
?>
if I understand correctly, what you want is to select all data that have eStatus value jump.
why not simply SELECT empID,startDate FROM tablerecord WHERE empID IN(SELECT MAX(ID) FROM tablerecord) AND eStatus = 'JUMP'?
or, if you want the unique value of empID, SELECT empID,startDate FROM tablerecord WHERE empID IN(SELECT DISTINCT(ID) FROM tablerecord) AND eStatus = 'JUMP'
all my query above will not produce any result
you might want to try multiple select in your query for a crude way to get it all in one go
select * from tablerecord where empID in(SELECT empID FROM tablerecord WHERE ID IN (SELECT MAX(ID) FROM tablerecord group by empID)) and eStatus = 'JUMP'
in this way, you only query the DB one time and the rest can be done with your PHP code
I would use this query to get all needed data :
# Get first and last jump for each empID
SELECT *
FROM tablerecord t1
WHERE t1.ID = (
SELECT MIN(t2.ID)
FROM tablerecord t2
WHERE t1.empID==t2.empID
) or t1.ID = (
SELECT MAX(t3.ID)
FROM tablerecord t3
WHERE t1.empID==t3.empID
)
And then some PHP to run through, comparing each pairs
$result = mysqli_query($con,"the_previous_query....");
$row_to_compare_with =false;
while ($row=mysqli_fetch_assoc($result )) {
if ($row_to_compare_with == false) {
$row_to_compare_with = $row;
} else {
// Compare $row_to_compare_with with $row, both having same empId
// do your thing here...
$row_to_compare_with = false;
}
}

SQL sum of columns in Codeigniter

I have a an SQL table as follows:
>--------------------------
>|ID | AMOUNT | PRODUC_ID |
>--------------------------
>|1 | 100 | 5
>|2 | 100 | 5
>|3 | 100 | 5
>|4 | 100 | 10
>|5 | 100 | 10
>|6 | 100 | 10
>|6 | 100 | 10
Im using codeigniter, Im expecting to get the SUM OF AMOUTS according to the PRODUCT_ID dynamically. the required output is:
>sum of prodcut_id 5 = 300
>sum of prodcut_id 10 = 400
Use group by to sum the amounts.
Cut-n-pasted from here.
$query = $this->db->query('select produc_id, sum(amount) as total_amt from mytable group by produc_id');
foreach ($query->result() as $row)
{
echo $row->produc_id;
echo $row->total_amt;
}
Try like this:
$this->db->select('PRODUC_ID, SUM(AMOUNT) AS AMOUNT', FALSE);
$this->db->group_by('PRODUC_ID');
$query = $this->db->get('TABLE_NAME');
$result = $query->result();

Displays WHERE for two conditions in the same column

-----------------------------------------------------
| id | posts_id | users_id | ratings |
-----------------------------------------------------
| 1 | 7 | 20 | 5 |
| 2 | 8 | 20 | 3 |
| 3 | 7 | 21 | 4 |
-----------------------------------------------------
Table name: mytable
\I want to make sure that ratings between posts_id and users_id are matched on the same column.
$query = $conn->query("SELECT ratings FROM mytable WHERE posts_id=7 and users_id=20");
$row = $query->fetch_array();
echo $row['ratings'];
This query does not work. I know there must be something wrong.
I want to get results: 5
What is the best query to show ratings?
----------------UPDATE-----------------------------
Sorry, my first problem lies with the connection, and now it is resolved.
But now there is a new problem.
I want to display the total sum of the rating results.
My new code
$Rate = $conn->query("SELECT * FROM mytable WHERE posts_id=7");
while ($Rated = $Rate->fetch_array()) {
echo $Rated['ratings'] + $Rated['ratings'];
}
For example on posts_id=7
Here I expect 5 + 4 = 9
But my code results exactly 54 + 54
How to fix this code?
For the updated question, this code should be work. We can use sum() function. Check here sum() function
$Rate = $conn->query("SELECT sum(ratings) as ratings FROM mytable WHERE posts_id=7");
while ($Rated = $Rate->fetch_array()) {
echo $Rated['ratings'];
}

Yii2 - Query count per day to ActiveRecord

I have the following table structure and using Yii2 ActiveRecord methods I'd like to extract the number of bookings (OrderLine) a supplier has for each day for the next week (0 entries also required). So some way of getting a row per day per supplier, with num_bookings or potentially 0 depending on the supplier.
/--------------------\ /------------\
| OrderLine |------------------|Availability|
|--------------------| 0..n 1 |------------|
|ID {PK} | |ID {PK} |
|availabilityID {FK} | |start |
|line_status | \------------/
|supplierID {FK} |
\--------------------/
| 1
|
|
| 1
/----------\
| Supplier |
|----------|
|ID {PK} |
\----------/
Querying the database directly, using DAO, with the following SQL gives me (almost) the desired result,
select count(ol.ID) as num_bookings,
day(from_unixtime(a.start)) as order_day,
ol.supplierID
from order_line ol left join
availability a on ol.availabilityID = a.ID
where ol.line_status = "booked"
and a.start >= 1451952000 //magic number for midnight today
and a.start <= 1452556800 //magic number for seven days from now
group by order_day, ol.supplierID;
something along the lines of
------------------------------------
| num_bookings|order_day|supplierID|
------------------------------------
| 1 | 5 | 3 |
| 2 | 5 | 7 |
| 1 | 6 | 7 |
| 1 | 7 | 7 |
------------------------------------
So there should be entries of 0 for the days the given Supplier has no bookings, like so
------------------------------------
| num_bookings|order_day|supplierID|
------------------------------------
| 1 | 5 | 3 |
| 0 | 6 | 3 |
| 0 | 7 | 3 |
| 2 | 5 | 7 |
| 1 | 6 | 7 |
| 1 | 7 | 7 |
------------------------------------
[days 8+ omitted for brevity...]
I've got some php/Yii code which will [eventually] give me something similar but involves multiple queries and database connections as follows,
$suppliers = Supplier::find()->all(); // get all suppliers
$start = strtotime('tomorrow');
$end = strtotime('+7 days', $start); // init times
// create empty assoc array with key for each of next 7 days
$booking_counts[date('D j', $start)] = 0;
for ($i=1; $i<7; ++$i) {
$next = strtotime('+'.$i." days", $start);
$booking_counts[date('D j', $next)] = 0;
}
foreach ($suppliers as $supplier) {
$bookings = OrderLine::find()
->joinWith('availability')
->where(['order_line.supplierID' => $supplier->ID])
->andWhere(['>=', 'availability.start', $start])
->andWhere(['<=', 'availability.start', $end])
->andWhere(['order_line.line_status' => 'booked'])
->orderBy(['availability.start' => SORT_ASC])
->all();
$booking_count = $booking_counts;
foreach ($bookings as $booking) {
$booking_count[date('D j', $booking->availability->start)] += 1;
}
}
This gives me an array for each supplier with the count stored under the appropriate day's index but that feels quite inefficient.
Can I refactor this code to return the desired data with fewer database calls and less 'scaffold' code?
This could be is the trasposition of your firt select
$results = OrderLine::find()
->select('count(order_line.ID) as num_bookings, day(from_unixtime(availability.start)) as order_day', order_line.supplierID )
->from('order_line')
->leftjoin('availability', 'order_line.availabilityID = availability.ID')
->where( 'order_line.line_status = "booked"
and a.start >= 1451952000
and a.start <= 1452556800')
->groupBy(order_day, order_line.supplierID)
->orderBy(['availability.start' => SORT_ASC])
->all();
in this way you should obtain a row for supplierID (and order_day) avoinding the foreach on supplier
For getting the data in $results->num_bookings and order_day you need add
public $num_bookings;
public $order_day;
in your OrderLine model
I hope this is what you are looking for.

Categories