Using PHP to GroupBy, looping through results and using count - php

I have search SO and found answers where people GROUP BY but haven't come across an answer where it displays the ability to GROUP BY (in this case date) and then get the user with the highest # of entries (in each of the date results).
I have my table set up as follows.
+----+------+-----------+-----------------+---------------------+
| id | name | reference | email | date |
+----+------+-----------+-----------------+---------------------+
| 1 | dan | 56453 | dan#example.com | 2015-05-01 09:00:01 |
| 2 | bob | 34564 | bob#example.com | 2015-05-01 09:21:03 |
| 3 | dan | 08948 | dan#example.com | 2015-05-01 09:30:08 |
| 4 | bob | 43775 | bob#example.com | 2015-05-02 09:01:43 |
| 5 | bob | 67210 | bob#example.com | 2015-05-02 09:04:13 |
| 6 | dan | 22195 | dan#example.com | 2015-05-02 09:09:11 |
+----+------+-----------+-----------------+---------------------+
Each day users log in and input a reference. Each day they could be logging many entries.
First, what I'm trying to do is GROUP BY the days and output the data.
So $day[0] which should equal "2015-05-01", should output those first 3 rows and who (and their count) has the highest number of entries for that day.
So output should be:
+----+------+-----------+-----------------+---------------------+
| Results of 2015-05-01 |
+----+------+-----------+-----------------+---------------------+
| 1 | dan | 56453 | dan#example.com | 2015-05-01 09:00:01 |
| 2 | bob | 34564 | bob#example.com | 2015-05-01 09:21:03 |
| 3 | dan | 08948 | dan#example.com | 2015-05-01 09:30:08 |
+----+------+-----------+-----------------+---------------------+
+----+------+-----------+-----------------+---------------------+
| Top user/s for 2015-05-01 |
+-----+-----+---------------------------------------------------+
| dan | 2 | |
+-----+-----+---------------------------------------------------+
So I need to be able to output the data for each day including the user with the most entries for that particular day.
My understanding is that I'd need to do something like this but can't quite grasp it.
$query = mysqli_query('SELECT * FROM mydata GROUP BY DATE(mydata.date as $date)');
$groupcount = 0;
while ($row = #mysqli_fetch_array($query))
{
$rowcount = 0;
$date[$groupcount] = $date;
$dayquery = mysqli_query('SELECT * FROM mydata WHERE date = $date)');
while ($entry = #mysqli_fetch_array($dayquery))
$data[] = array($row['$rowcount']['name'], $row['$rowcount']['reference'], $row['$rowcount']['email'], $row['$rowcount']['date']);
foreach ($data as $d) {
echo "Name: " . $d[0] . ", Reference: " . $d[1] . ", Email: " . $d[2] . ", Date: " . $d[3];
}
$rowcount++;
}
So something like that but also having another query that will output the person and the sum of the highest entries for that day. I just don't want to add another query as I think there would be a better way of structuring this to include COUNT in another.
Could potentially be multiple people with the same number of entries for the day so I'm trying to accommodate for that.

This should give you what you are looking for all in one query.
SELECT
max(m.id), -- since this column is unique you can ignore it if it's not important, or using min/max to get one of the values
max(m.reference), -- since this column appears to be unique you can ignore it if it's not important, or using min/max to get one of the values
m.name,
m.email,
cast(m.date as date) date,
count(*) count
FROM
mydata m
GROUP BY
m.name,
m.email,
cast(m.date as date)
ORDER BY
m.date DESC,
m.count DESC,
m.name ASC,
m.email ASC;

Related

Eloquent get last record groupped by date

I have a table prices with where I store more times in a day more values referred to a customer like this:
Table prices:
| id | customer_id | value_1 | value_2 | value_3 | created_at |
-------------------------------------------------------------------------
| 1 | 10 | 12345 | 122 | 10 | 2021-08-11 10:12:40 |
| 2 | 10 | 22222 | 222 | 22 | 2021-08-11 23:56:20 |
| 3 | 12 | 44444 | 444 | 44 | 2021-08-12 08:12:10 |
| 4 | 10 | 55555 | 555 | 55 | 2021-08-13 14:11:20 |
| 5 | 10 | 66666 | 666 | 66 | 2021-08-13 15:15:30 |
| 6 | 10 | 77777 | 777 | 77 | 2021-08-13 16:12:50 |
I have some filters on that table to retrieve only records with date greater than X and/or lower than Y, sort records by value_1 or value_2, etc...
With that filters I have to take only 1 record for each day of a customer specified.
I'm able to get the record with the highest value_1 for example, by using sql function max() and group by date.
// Init query
$query = Price::query();
// Take the greatest value of value1
$query = $query->selectRaw(
'max(value_1) as highest_value_1, ' .
'date(created_at) as date'
);
// If defined, add a greater or equals
if ($from) $query->where("created_at", ">=", $from);
// If defined add a lower or equals
if ($to) $query->where("created_at", "<=", $to);
// Get results for current customer only, grupping by date and ordering it
$query = $query->where('customer_id', $id)->groupBy('date')
->orderBy('date', 'DESC');
// Fetch records
$records = $query->get();
But now I would like to have only the last record for each day of a customer specified.
I need an eloquent/sql solution because the date range to search may be large and the table has a lot of records.
How can I archive that?
Thanks
Not a complete solution (no customer filter nor laravel use), but I would use something like that in pure sql :
SELECT
CONCAT(EXTRACT(YEAR_MONTH FROM created_at),EXTRACT(DAY FROM created_at)) AS day,
MAX(created_at)
FROM mytable
GROUP BY day;
Of course, you may use other function to group by day (like string regexp or substr).

Mysql query to join two table and group by matching id

Am trying to group user orders by the order id, but am not getting it right i know this will be first get done in the SQL query then organise it well in PHP and HTML but i don't know how to get it done.
orderinfo
oid | userid | total | payid
-----|---------|--------|----------
oi10 | peter | 650 | VCC-100
oi12 | john | 30 | VCC-500
oi15 | peter | 60 | COD-500
itemorder
pid | ioid | userid | price | qty | itemname
----| ------|---------|--------|-----|-----------
p10 | oi10 | peter | 200 | 1 | lexus
p20 | oi10 | peter | 150 | 1 | Toyota
p15 | oi10 | peter | 300 | 1 | Myvi
p66 | oi15 | peter | 25 | 2 | BMW
p67 | oi15 | peter | 10 | 1 | Saga
p67 | oi12 | john | 10 | 3 | Saga
My current Code
$handler->prepare('
SELECT * FROM itemorder io
LEFT JOIN orderinfo oi
ON io.oid = oi.ioid
WHERE io.userid = 'peter'
GROUP BY io.oid
ORDER BY oi.pid DESC
');
$handler->execute();
$RecentOrder = $handler->getAll();
$handler->free();
if(!empty($RecentOrder)){
foreach($RecentOrder as $row){
}
}
Expected Result
I want the result to be sorted according to the order id all item that has same order id will be listed (list according to order id).
oid: oi10
--------
lexus
Toyota
Myvi
---------------------
oid: oi15
--------
BMW
Saga
The desired output can be retrieved with just ORDER BY.
SELECT *
...
ORDER BY oi.oid DESC, io.pid DESC
And then do the specific formatting in PHP. Easiest way is probably to remember the order_id of the last row.
$lastOrderId = null;
foreach ($result as $row) {
if ($lastOrderId != $row['oid']) {
echo 'oid: ' . $row['oid'] . PHP_EOL;
echo ' -----------' . PHP_EOL;
}
echo ' ' . $row['itemname'] . PHP_EOL;
$lastOrderId = $row['oid'];
}
You can try this :
SELECT io.ioid,GROUP_CONCAT("",io.itemname) as order_items FROM itemorder as io
LEFT JOIN orderinfo as oi
ON io.ioid = oi.oid
WHERE io.userid = 'peter'
GROUP BY io.ioid
ORDER BY io.pid DESC
Please not the columns on which join is done.
Then in PHP you can use explode function to get the array of names for each order.
Hope this helps!

Use file_get_contents in PHP Array to Update MySQL

I have a database contains ID and name of my Staff (DATABASE 1):
--------------
| ID | name |
--------------
| 1 | Mr.AA |
| 2 | Mr.AB |
|... | ... |
| 78 | Mr.CZ |
--------------
Then my colleague has the staff absence database per day for 2 years (DATABASE 2):
Tablename: Table_for_Mr.AA
--------------------------
| ID | date | work |
--------------------------
| 1 | 2016-01-01 | Yes |
| 2 | 2016-01-02 | Yes |
| 3 | 2016-01-03 | No |
|... | ... | ... |
|730 | 2017-12-31 | Yes |
--------------------------
Due to our agreement, we hold each database ourselves (2 parties), so each database is stored in different server.
Lately I need to get the data from DATABASE 2 to be shown in my website and I can ask my colleague to make PHP file that return the array for each name (www.colleaguewebsite/staff/absence.php?name=Mr.AA).
I already made the new 'workstat' database (DATABASE 3) in my server with this detail:
---------------------------------
| ID | date | Name | work |
---------------------------------
| 1 | 2016-01-01 |
| 2 | 2016-01-02 |
| 3 | 2016-01-03 |
|... | ... |
---------------------------------
this is the best I can do:
$sourceURL = 'www.colleaguewebsite/staff/absence.php'
$sql1= $conn->query("select * FROM staff ");
while($row_1 = $sql1->fetch_array()){
$name= $row_1 ['name'];
//getting the absence detail from each staff
$json_1 = file_get_contents($sourceURL.'?name='.$name);
$data_1 = json_decode($json_1,true);
foreach($data_1 as $value_1){
$date = $value_1['date'];
$work = $value_1['work'];
//if the correspondence date is exist then update, otherwise add
$sql_2 = $conn->query("select * FROM workstat WHERE date='$date' AND name='$name");
if ($sql_2->num_rows > 0){
$update=$conn->query("UPDATE workstat set name='$name', work='$work' WHERE date='$date' ");
}else{
$addnew=$ob->query("INSERT INTO availability (date, name, work) VALUES ('$date', '$name', '$work'
}
}
}
However, I have some things that bothers:
The required time to execute this script is very long, mostly exceeding the 90 seconds time.
Dirty database. I will have 730 row of data (per day) for each name, so my database 3 will have 730 * 78 person = 56.940 rows with duplicate date (2017-01-01 ... 2017-12-31 for Mr.AA, 2017-01-01 ...2017-12-31 for Mr.AB, etc...).
How can I optimize my code in table design and loading time?
Another method than file_get_contents is okay, I hope it's still PHP.

Get count of fields with a specific value in a row? mysqli-php

please assume this as the table
tablename- schemeOverview
| slno |schemename | amount| date2 | date3 | date4 ...daten |
|---------|-----------|-------|-------|-------|-------|----------|
| 1 | Cell | 1000 | DUE | DUE | | |
| 2 | Cell | 1000 | PAID | PAID | | |
| 3 | Cell | 1000 | DUE | DUE | DUE | |
| 4 | Cell | 1000 | PAID | PAID | | |
| 5 | Cell | 1000 | DUE | DUE | | |
I am trying to count the number of fields that have value as 'PAID' .
for example the count of PAID for slno-2 should be 2.
the number of date columns varies per table but I have the count of date columns for a table.So a better option would be to check all fields of the specified row(slno)
you can use this code
SELECT slno,count(*) AS paid
FROM schemeOverview
WHERE 'PAID' IN (date2, date3, date4,...,daten)
Well after a lot of brain drain I came up with this and It works!
$paidCount=0;
$sql2 = "SELECT * FROM " .$scheme_name. " WHERE slno = " .$recBookNo;
$result2 = mysqli_query($conn,$sql2);
if($result2)
{
while ($row19 = $result2->fetch_assoc())
{
foreach ($row19 as $key => $value)
{
if(($value)=='PAID')
{
$paidCount++;
}
}
}
}
You can use count()
SELECT count(date2) as cd2 FROM schemeOverview WHERE date2 = "PAID"
This will store the value into cd2, in this case 2

PHP stack multiple values into one value

This is the bookings table I'm using for my query
+----------------------+
| event_id | person_id |
+----------------------+
| 5 | 7 |
| 4 | 7 |
| 3 | 7 |
| 4 | 5 |
| 3 | 5 |
| 5 | 3 |
+----------------------+
This table shows that person_id 7 has 3 bookings, 5 has 2 bookings and 3 has 6 bookings.
Currently, I'm using this query to get the total number of bookings per person.
$query='
SELECT
bookings.person_id,
COUNT(bookings.person_id) AS total,
bookings.event_id,
users.display_name
FROM bookings
INNER JOIN users ON bookings.person_id=users.id
WHERE users.id=bookings.person_id
GROUP BY bookings.person_id';
$result = mysql_query($query);
if($result) {
while($row = mysql_fetch_array($result))
{
/* total bookings per user */
$value = $row['total'];
$sum += $value;
/* events booked per user */
$events....
/* Displaying results */
echo "<tr width='500'>";
echo "<td>".$row['person_id']."</td>";
echo "<td>".$row['display_name']."</td>";
echo "<td>".$row['total']."</td>";
echo "<td>".$events."</td>";
echo "</tr>";
}
This works okay and gives me:
+-----------------------------------+
| ID | NAME | Total Bookings |
+-----------------------------------+
| 7 | Bob | 3 |
| 5 | Jane | 2 |
| 3 | Joe | 1 |
+-----------------------------------+
I'm seeking help to get this to display the events booked by each person (like the 4th columns below):
+------------------------------------------------+
| ID | NAME | Total Bookings | Event IDs |
+------------------------------------------------+
| 7 | Bob | 3 | 5,4,3 |
| 5 | Jane | 2 | 4,3 |
| 3 | Joe | 1 | 5 |
+------------------------------------------------+
Could you please help me getting there.
Thanks.
GROUP_CONCAT https://dev.mysql.com/doc/refman/5.0/en/group-by-functions.html#function_group-concat
$query='
SELECT
bookings.person_id,
COUNT(bookings.person_id) AS total,
GROUP_CONCAT(bookings.event_id) as event_ids,
users.display_name
FROM bookings
INNER JOIN users ON bookings.person_id=users.id
WHERE users.id=bookings.person_id
GROUP BY bookings.person_id';
A bit different query but same result:
SELECT
bookings.person_id,
COUNT(
bookings.person_id
) AS total,
users.display_name,
GROUP_CONCAT(
bookings.event_id
ORDER BY
bookings.event_id
) AS events_list
FROM
bookings,
users
WHERE
bookings.person_id=users.id
GROUP BY
bookings.person_id
ORDER BY
bookings.person_id
I don't know if for a large data, the execution time is less, more or equal.

Categories