MySQL group by value and max date - php

I need to extract the last character of columns result_1 and result_2 and group them so I have a list from 0 to 9 indicating when it was generated.
In the folowing code I managed to obtain a list from 0 to 9 but the date is the earliest date in the table and not the latest.
$sql = "SELECT * FROM ((SELECT RIGHT(result_1, 1) AS results, date
FROM act_results ORDER BY date ASC)
UNION ALL (SELECT RIGHT(result_2, 1) AS results, date
FROM act_results)) s WHERE results != ''";
$sql .= " GROUP BY results";
$table = mysql_query($sql);
while ($row = mysql_fetch_array($table)) {
echo $row['results']." (".$row['date'].") <br>";
}
Any ideas how to fix it?
Thanks in advance.

Use group by with max():
SELECT results, max(date)
FROM ((SELECT RIGHT(result_1, 1) AS results, date
FROM act_results
) UNION ALL
(SELECT RIGHT(result_2, 1) AS results, date
FROM act_results
)
) s
WHERE results <> ''
GROUP BY results;

Related

How to select users with their amount list and sum amount using SUM(CASE) with a date interval

I have a table which contains list of users and the amount they save per day. I want to select all the money they save per day and also list all their details(amount) they have saved.
Issue: I couldn't find the sum for that date interval
SELECT
cust_name,
ac_no,
amount,
SUM(CASE WHEN (trans_date > DATE_SUB(NOW(), INTERVAL 1 MONTH))
THEN amount ELSE 0 END) as todalTotal from contributions
where username = 'james12'
GROUP BY id
This is what I am trying to achieve
$que = mysqli_query($con,"SELECT cust_name,
ac_no,
amount FROM contributions
WHERE username='$username'
"
);
while($row = mysqli_fetch_array($que))
{
$sql =mysqli_query($con,"SELECT SUM(amount) as total FROM contributions WHERE trans_date > DATE_SUB(NOW(), INTERVAL 3 DAY) AND username='$username' ");
$rows = mysqli_fetch_array($sql);
echo $rows["total"] . "<br>";
echo $row["cust_name"] . "<br>";
}
$rows["total"] will appear the number of times
$row["cust_name"] appears which I don't want. I want
$rows["total"] to appear just once.
You have to select the coloumn and then tell where this is located. Then just use use SUM.
SELECT SUM(amount) AS AmountSaved
FROM yourtable
SQLdatabase
select user_name,sum(amount) as total_amount,date_format(trans_date,'%Y-%d-%m') as transDate
from table_name
group by user_name,date_format(trans_date,'%Y-%d-%m')

SELECT count from multiple tables between 2 dates with BIG DATA

I have multiple tables (same column structures) which I want to have the count rows between 2 date ranges. Right now it gives me all records from each table. Each table have around 700K records, which makes it also slow to search through.
I'm not getting the right query for this.
The below query is what I have so far.
$monday = '2018-01-15';
$tuesday = '2018-01-16';
SELECT count(datetime) FROM uptime_m1 WHERE datetime
BETWEEN '$monday' and'$tuesday' and status = 'idle'
UNION ALL
SELECT (datetime) FROM uptime_m2 WHERE datetime
BETWEEN '$monday' and'$tuesday' and status = 'idle';
PHP CODE:
if ($result = $mysqli->query("
SELECT count(datetime) FROM uptime_m1 WHERE datetime
BETWEEN '$monday' and'$tuesday' and status = 'idle'
UNION ALL
SELECT (datetime) FROM uptime_m2 WHERE datetime
BETWEEN '$monday' and'$tuesday' and status = 'idle';
")) {
$row_cnt = $result->num_rows;
$count_m1_idle_monday = $row_cnt;
$result->close();
}
You can use a subrequest to count each table and sum the result.
select
(select count(*) from uptime_m1
where datetime between '$monday' and '$tuesday' and status = 'idle')
+ (select count(*) from uptime_m2
where datetime between '$monday' and '$tuesday' and status = 'idle')
as nbrows;

Mysql IFNULL working only once in a multiple SELECT query

I'm trying to build a month graphic using a MySQL query. I'm checking how many rows there are in a table for each month in a single query using the UNION command. Example with 3 months bellow:
$query =
"SELECT IFNULL((SELECT SUM(score) FROM statistics WHERE MONTH(date) = 1), 0) AS total UNION
SELECT IFNULL((SELECT SUM(score) FROM statistics WHERE MONTH(date) = 2), 0) AS total UNION
SELECT IFNULL((SELECT SUM(score) FROM statistics WHERE MONTH(date) = 3), 0) AS total";
$stats_query = mysqli_query ($db_connection, $query);
$result = "";
while ($row = mysqli_fetch_assoc($stats_query)) {
$result .= $row['total'].",";
}
echo ($result);
// OUTPUT: 0,176,68,
As you can see, I'm telling mysql to return me a "0" in case there are no rows for that month (which is the case for January).
There are a total of 12 SELECTS in that query (I copied just 3 to save space), one for each month. Some months will return a value, others won't (which the IFNULL should then convert to a "0").
My final output, for all the 12 months, should look like this:
// OUTPUT: 0,176,68,0,0,0,0,0,12,15,176,43,
BUT... if there is more than one SELECT that returns no rows, the query won't add another "0" to the result. My final result ends up being like this:
// OUTPUT: 0,176,68,12,15,176,43,
It's like the IFNULL is only executed once, even though he's present in all the 12 SELECTS...
Am I doing something wrong? Can anyone spot an error in my code or something?
Thank you!
Use UNION ALL instead of UNION to get all results:
SELECT IFNULL((SELECT SUM(score) FROM statistics WHERE MONTH(date) = 1), 0) AS total UNION ALL
SELECT IFNULL((SELECT SUM(score) FROM statistics WHERE MONTH(date) = 2), 0) AS total UNION ALL
SELECT IFNULL((SELECT SUM(score) FROM statistics WHERE MONTH(date) = 3), 0) AS total
UNION returns only DISTINCT rows.
From doc:
The default behavior for UNION is that duplicate rows are removed from
the result.

Setting null values to dates that aren't in MySQL

So, I am fetching some data from MySQL with that code:
<?
$query=mysql_query("SELECT date,COUNT(*) as num FROM downloads WHERE prjID='".$_GET['id']."' GROUP BY date ORDER BY date ASC");
$num=mysql_num_rows($query);
$res='';
$i=0;
while($row=mysql_fetch_array($query)){
$i++;
$date=date("d.m.Y", strtotime($row['date']));
$dan=date("d", strtotime($row['date']));
$mesec=date("m", strtotime($row['date']));
$leto=date("Y", strtotime($row['date']));
if($i=1){
$danPrvi=$leto.", ".($mesec-1).", ".$dan;
$dan1=date("d", strtotime(time()));
$mesec1=date("m", strtotime(time()));
$leto1=date("Y", strtotime(time()));
$danZadnji=$leto1.", ".($mesec1-1).", ".$dan1;
}
$numb=1;
if($row['num']!=1){
$res.="[Date.UTC(".$leto.",".($mesec-1).",".$dan."),".$row['num']."], ";
}
else{
if($i!=$num){
$res.="[Date.UTC(".$leto.",".($mesec-1).",".$dan."),".$numb."], ";
}
else{
$res.="[Date.UTC(".$leto.",".($mesec-1).",".$dan."),".$numb."]";
}
}
}
?>
And I get results like that:
1.3.2013 - 1
6.3.2013 - 5
But I would like to get results like that:
1.3.2013 - 1
2.3.2013 - 0
3.3.2013 - 0
4.3.2013 - 0
5.3.2013 - 0
6.3.2013 - 1
I am also using Highcharts, so date values must be formatted like Date.UTC(year, month-1, day)
EDIT:
I don't have all dates in my databases. In my examle, there are only 1.3.2013 and 6.3.2013, so how would I detect and set 0 value for all dates between, that don't have a value >=1?
I imagine what you need to do is set up a construct to hold the dates you are interested in and either use that in your query or post processing the query data. For example:
<?php
$query=mysql_query("SELECT date,COUNT(*) as num FROM downloads WHERE prjID='".$_GET['id']."' GROUP BY date ORDER BY date ASC");
$num=mysql_num_rows($query);
// Get the first and last dates in the result set
$firstRow = mysql_result($query, 0);
$lastRow = mysql_result($query, $num-1);
// Now make thos the begin and end dates
$beginDate = new DateTime(strtotime($firstRow['date']));
$endDate = new DateTime(strtotime($lastRow['date']));
$currentDate = $beginDate;
$interestingDates = array();
// Populate our interestingDates array with all counts set to 0
while ($currentDate <= $endDate){
$interestingDates[$currentDate->format('d.m.Y')] = 0;
$currentDate->add(new DateInterval('P1D'));
}
// Reset the data result for looping over
mysql_data_seek($query,0);
while($row=mysql_fetch_array($query)){
// Go ahead and format the string
$formatedString = date("d.m.Y", strtotime($row['date']));
// If the string is in our interestingDates array, update the count
if (array_key_exists($formatedString, $interestingDates)){
$interestingDates[$formatedString] = $row['num'];
}
}
// Print it out
foreach ($interestingDates as $key=>$value){
print "$key - $value\n";
}
NOTE 1: mysql_query is deprecated as of PHP 5.5.0 and will be removed in the future. Pleasue use another API - I recommend pdo_mysql.
NOTE 2: The current query is not parameterized. Using PDO, this would perhaps look like:
$sth = $dbh->prepare('SELECT date,COUNT(*) as num FROM downloads WHERE prjID= :prjID GROUP BY date ORDER BY date ASC');
$sth->bindParam(':prjID', $_GET['id'], PDO::PARAM_INT);
$sth->execute();
Disclaimer - I haven't actually run this code, I just wrote it off the top of my head. You might need to test/debug it.
Assuming you have data for all dates, just not for a particular id, you can do a condition sum:
SELECT date, sum(case when prjID='".$_GET['id']."' then 1 else 0 end) as num
FROM downloads
GROUP BY date
ORDER BY date ASC
WARNING! It's a very bad style to do it in SQL, but if you want -- you can :)
http://sqlfiddle.com/#!2/b491a/1/0
SELECT dynamic_date AS date, COUNT(downloads.date) AS num FROM (
SELECT DATE_ADD(start, INTERVAL i - 1 DAY) AS dynamic_date, prjID FROM
(
SELECT #i := #i + 1 AS i FROM
(SELECT 0 UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) t1,
(SELECT 0 UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) t2,
(SELECT 0 UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) t3,
(SELECT #i:=0) init
) i_sequence,
(SELECT MIN(date) start, MAX(date) finish, prjID FROM downloads WHERE prjID=5 GROUP BY prjID) minmax
WHERE DATE_ADD(start, INTERVAL i - 1 DAY) <= finish
) date_sequence
LEFT JOIN downloads ON dynamic_date = downloads.date and downloads.prjID=date_sequence.prjID
GROUP BY dynamic_date
;

how to minimize my query?

i want to minimize my query
"SELECT * FROM tb_videos GROUP BY DATE(added) ORDER BY DATE(added) desc"
after get result
foreach($result as $rst)
{
$dt=date('Y-m-d',strtotime($rst->added));
SELECT * FROM tb_videos WHERE DATE(added)='$dt' ORDER BY added desc
}
Can i do with single query?
Your queries make no sense. First you are selecting the DISTINCT dates (ignore time) from the data. Then for each date, you.. select all data for that date?
Why don't you just fire one query
SELECT *, DATE(added) as DateNoTime
FROM tb_videos
ORDER BY added desc
If you only want 5 dates, and the table is large, there are two possibilities.
1, There are never gaps in dates, you can use
SELECT *, DATE(added) as DateNoTime
FROM tb_videos
WHERE added >= ADDDATE(CURDATE(), interval -4 days)
ORDER BY added desc
2, If there may be gaps, e.g. nothing for yesterday so it has to show last 5 days that have records
SELECT *, DATE(added) as DateNoTime
FROM (
select min(DateNoTime) as MinDate
from
(
select DATE(added) as DateNoTime
FROM tb_videos
order by DateNoTime desc
limit 5
) x) y, tb_videos
WHERE added >= y.MinDate
ORDER BY added desc
This gives you all the data. In PHP, keep track of DateNoTime. Whenever that changes, you are in a different date, which would have previously caused you to fire another query. The code should otherwise only change minimally.
Unchecked PHP code
$result = mysql_query('
SELECT *, DATE(added) as DateNoTime
FROM (
select min(DateNoTime) as MinDate
from
(
select DATE(added) as DateNoTime
FROM tb_videos
order by DateNoTime desc
limit 5
) x) y, tb_videos
WHERE added >= y.MinDate
ORDER BY added desc
');
$prevdate = NULL;
foreach($result as $rst)
{
if($prevdate!=$rst=>DateNoTime) {
// do something, like printing out a header for each new date
$prevdate=$rst=>DateNoTime;
}
// do something with the record
}
You want to minimise the records found? use a where clause to choose your specific records
"SELECT * FROM tb_videos WHERE videogroup = action GROUP BY DATE(added) ORDER BY DATE(added) desc"
For example
SELECT * FROM tb_videos WHERE DATE(added) = curdate() ORDER BY added desc

Categories