Avoiding PHP workaround for double GROUP BY sql statement - php

I would like to make a SQL query of counted grouped results. The only way I was able to do it was with the help of PHP. But I am sure that it is possible to do it in one SQL statement.
The table's structure is the following:
id, user_hash, timestamp
And my little PHP workaround looks like this:
$sql = 'SELECT count(id) AS \'total clicks\' FROM stats WHERE timestamp > UNIX_TIMESTAMP(NOW() - INTERVAL '.$num_days.' DAY) GROUP BY user_hash ORDER BY count(id) DESC';
$result = $mysqli->query($sql);
$count = array();
while ($row = mysqli_fetch_assoc($result)) {
if (isset($count[$row['total clicks']])) {
$count[$row['total clicks']]++;
} else {
$count[$row['total clicks']] = 1;
}
}
foreach ($count as $k => $v) {
echo $v." users clicked ".$k." times\n";
}
I am probably going to kick myself how easy it is, but I just can't seem to get to an all-in-one SQL solution. :)

Please try:
$sql = 'SELECT
A.`user_times_clicked`,
COUNT(A.user_hash) AS `user_count`
FROM(
SELECT
count(id) AS `user_times_clicked`,
user_hash
FROM
stats
WHERE
timestamp > UNIX_TIMESTAMP(NOW() - INTERVAL '.$num_days.' DAY)
GROUP BY
user_hash
) AS A
GROUP BY
A.`user_times_clicked`
ORDER BY
COUNT(A.user_hash) DESC'
I hope it helps.

Related

How to count contents of last n rows mysql

I am trying to figure out how to see how many times in the past 7 entries/rows that sleep = 1.
Currently, $num shows the number of times sleep = 1 in all rows. I have seen that 'order by xxx desc limit 7' has been suggested in other answers but it doesn't seem to work well in this scenario. Would greatly appreciate any help, thanks!
Heres my code:
$result = mysqli_query($conn, "SELECT count(*) FROM test_table WHERE sleep = 1");
$row = mysqli_fetch_row($result);
$num = $row[0];
You can try this one:
SELECT a, COUNT(b) FROM test_table
WHERE sleep = 1
GROUP BY a
ORDER BY COUNT(b) ASC
LIMIT 7
Here, a is the name of your column you are trying to count
And, b is any column name for usage to count (it can id, or any column name)
If the sleep is binary/tinyint you can just sum that in the query with the order by.
SELECT sum(sleep)
FROM table
ORDER BY COUNT(id) DESC
LIMIT 7
If sleep isn't binary you can use a case statement.
SELECT sum(case when sleep = 1 then 1 else 0 end) as totalsleep
FROM table
ORDER BY COUNT(id) DESC
LIMIT 7
Here's my idea, get all the data in test_table and create a loop that will count the sleep, like this
$result = mysqli_query($link, "SELECT sleep FROM test_table;");
$x=1;
$sleep = [];
$SleepCount= 0;
while($row = mysqli_fetch_array($result)) {
if($row[0] == "1"){
$SleepCount++;
}
if($x == 7){
array_push($sleep,$SleepCount);
$SleepCount = 0;
$x=0;
}
$x++;
}
echo "<pre>",print_r($sleep),"</pre>";

Codeigniter: display two data in query with distinct and count

I'm try to display two data of one query using codeigniter.
$query = "SELECT count(distinct p.id_paciente), count(c.pacientes_id_paciente) FROM paciente p, cita c WHERE p.id_paciente=c.pacientes_id_paciente AND p.usuarios_id_usuario=43 AND p.aseguradoras_id_aseguradora=8 AND c.dia_cita>='2015-04-16' AND c.dia_cita<='2015-04-16'";
$sql = $this->db->query($query);
How can I to show the two results of count(distinct p.id_paciente) and the count(c.pacientes_id_paciente)
I try using
foreach ($sql->result_array() as $row)
{
echo $row['id_paciente'];
echo $row['pacientes_id_paciente'];
}
But only display the content of the array...
Thanks
There are several issues with your code:
Use aliases to name columns in the resultset to be able to address them later by name
SELECT COUNT(distinct p.id_paciente) AS count1, ...
^^^^^^
Don't interpolate query strings yourself. Use Codeigniter's query bindings
This may not be relevant to you but if dia_cita has time component to it (i.e. is of type datetime) you may want to change your WHERE condition to
c.dia_cita >= ? AND c.dia_cita < ? + INTERVAL 1 DAY
There is no need for foreach loop. You always get only one row with this query. Therefore use Codeigniter's row() or row_array().
That being said your code may look like
$sql = "
SELECT COUNT(DISTINCT p.id_paciente) AS count1,
COUNT(c.pacientes_id_paciente) AS count2
FROM paciente p JOIN cita c
ON p.id_paciente = c.pacientes_id_paciente
WHERE p.usuarios_id_usuario = ?
AND p.aseguradoras_id_aseguradora = ?
AND c.dia_cita >= ?
AND c.dia_cita < ? + INTERVAL 1 DAY
";
$bindings = array(43, 8, '2015-04-16', '2015-04-16')
$row = $this->db
->query($sql, $bindings)
->row_array();
echo $row['count1'], $row['count2'];

Best way to sum and seperate by date in MYSQL with/witout php

Hi i have such table information:
what i want to do with php with while or just in mysql, is to SUM (time_used) of the rows with status 44 until its reached row with status 55. after that it should begin from start with new summing.
first query should return 37, second 76 (keep in mind it should be universal, for unlimited occurrences of 55 status row)
i thought of a way with time/date filtering and have this:
select sum(time_used) as sumed
from timelog
where start_time > (select end_time from timelog where (status='55')
ORDER BY id DESC LIMIT 1) ORDER BY id DESC
but this works only for last combination of 44 and 55
i know i will need two way filtering( < end_time and > end_time) so it will work for all cases, but cant think of a way to do it in php
can anyone help me?
EDIT:
sqlfiddle whoever want it:
http://sqlfiddle.com/#!2/33820/2/0
There are two ways to do it: Plain SQL or PHP. If you treat thousands of rows, it may be interresting to choose between the two by testing performance.
Plain SQL
select project_id, task_id, user_id, sum(time_used) as time_used,
min(start_time) as start_time, max(end_time) as end_time, max(comment) as comment from
(select t.id, t.project_id, t.task_id, t.user_id, t.time_used,
count(t2.id) as count55, t.start_time, t.end_time, t.comment
from timelog t
left join timelog t2 on t.id>t2.id and t2.status=55 and t.task_id=t2.task_id
group by t.id) as t
group by count55;
I assume here that a task can belong to one user only
SQL and PHP
$link = mysqli_connect( ... );
$query = "select id, project_id, task_id, user_id, time_used, start_time, end_time, status
from timelog order by id";
$result = mysqli_query($link, $query);
$table = array();
$time_used = 0;
$start_sum = true;
$i = 0;
while($row = mysqli_fetch_assoc ($result)){
if($start_sum){
$table[$i] = $row;
$start_sum = false;
} else {
$table[$i]['time_used'] += $row['time_used'];
$table[$i]['end_time'] += $row['end_time'];
}
if($row['state'] == 55){
$i++;
$start_sum = true;
}
}
If two tasks can run in simultaneously, solution 1 will work, but solution 2 will need to be adapted in order to take this in account.
here is my intepretation:
http://sqlfiddle.com/#!2/33820/45
set #n=0;
select project_id, task_id, user_id,sum(time_used) from (
SELECT time_used,project_id, task_id, user_id,
#n:=if(status=55,#n+1,#n),
if(status=55,-1,#n) as grouper FROM timelog
) as t
where grouper>-1
group by grouper;
I'm neither a php nor MySQL programmer, but I can explain the logic you want to follow. You can then code it.
First, query your db and return the results to php.
Next, set two sum variables to 0.
Start looping through your query results. Increment the first sum variable until you reach the first row that has status 55. Once you do, start incrementing the second variable.
The tricky part will be to sort your query by the row number of the table. Here is a link that will help you with that part.

Complex select statement

I have 4 tables
Tbl_Items:
Asset Id,
Asset_name,
Workshop,
PAT_PASS
(workshop, and PAT_PASS are either YES or NO. Workshop = YES and PAT_PASS = NO means this item is not available for hire..)
Tbl_Project_details:
Project_id,
Project_start_date,
project_end_date
TBL_Project_items:
Project_id,
Asset_id,
Start_date,
End_date
I need to do a select statement that allows me to show all the items in tbl_Items EXCEPT:
1) Those that are already in use on another project on the dates that I need them.
2) Are in the workshop. (Workshop = YES)
3) Are not PAT Tested (PAT_PASS = NO)
So far I have started with a simple statement like this:
$post_project_id = "13-1309.01"; //this is just an example number..
$sql =
"SELECT * FROM Project_details
Where Project_id = '$post_project_id' ";
$result = mysql_query($sql);
while ($row = mysql_fetch_array($result))
{
$hire_start_date = $row['Start_date']; // we find out our projects start date
$hire_end_date = $row['End_date']; // we find out our projects end date
}
$result=mysql_query("SELECT Items.Asset_id, Items.Name
FROM
Items,Project_items
WHERE
Project_details.Start_date < '$hire_start_date'
AND
Project_details.End_date > '$hire_end_date'")
or die(mysql_error());
while($row = mysql_fetch_array($result))
{
// fill up an option box with the results
}
Even this basic script doesn't seem to work! This is the first time I have tried selecting from multiple tables, so this is a steep learning curve!
Thanks!
I would go with a subquery:
SELECT * FROM Tbl_Items AS i WHERE
this should matches your (1.) condition: "take only those records, which with that select dont have any occurences":
0 = (
SELECT COUNT(1) FROM TBL_Project_items AS pi
WHERE i.Asset_Id = pi.Asset_Id
AND Start_date < $hire_start_date
AND End_date > $hire_end_date
)
workshop condition (2.):
AND WORKSHOP != "YES"
pat tested condition (3):
AND PAT_PASS != "NO"
$StartDate and $EndDate are your date constraints:
SELECT ITEM.asset_id,
ITEM.asset_name,
ITEM.workshop,
ITEM.pat_pass
FROM Tbl_Items ITEM
LEFT JOIN Tbl_Project_Items PJITEM
ON PJITEM.asset_id = ITEM.asset_id
AND PJITEM.start_date BETWEEN $StartDate AND $EndDate
OR PJITEM.end_date BETWEEN $StartDate AND $EndDate
WHERE ITEM.workshop = 'no'
AND ITEM.pat_pass = 'yes'
AND PJITEM.asset_id IS NULL
Who's Pat?
One problem:
WHERE
Project_details.Start_date < '$hire_start_date'
AND
Project_details.End_date > '$hire_end_date'")
The columns "Start_date" and "End_date" aren't in the "Project_details" table. In that table, those columns seem to be named "Project_start_date" and "Project_end_date".

Does mysql_fetch_array reset the query var?

For example I have a mysql query that gets some data. Then runs another query based some of the data that it got.
If i just return the first query, in my case $qOne. Everything works great.
BUT, after using my while loop while ($row = mysql_fetch_array($qOne)) It then returns as an empty array. (but the second query I return DOES work)
I tried to see if I could "save" the first query in another var im not messing with like this $savedResult = $qOne, then i'd just return the $savedResult but that did not work.
Does anyone know how I can get my function below to return both of the results? Thanks!
function getFoods($sort, $start, $limit) {
$qOne = mysql_query("SELECT a.id, a.name, a.type, AVG(b.r) AS fra, COUNT(b.id) as tvotes FROM `foods` a LEFT JOIN `foods_ratings` b ON a.id = b.id GROUP BY a.id ORDER BY fra DESC, tvotes DESC LIMIT $start, $limit;");
$i = 0;
$qry = "";
while ($row = mysql_fetch_array($qOne)) {
$fid = $row['id'];
if ($i > 0)
$qry .= " UNION ";
$i++;
$qry .= "SELECT fid, ing, amount FROM foods_ing WHERE fid='$fid'";
}
$qTwo = mysql_query($qry);
return array($qOne, $qTwo);
}
When you have returned the two query result resources, remember that you will need to fetch from them when you actually want to use them. (we don't see the code where you implement that).
To make use of $qOne after you already have looped through it, you must rewind it back to the first position. That is done with mysql_data_seek()
mysql_data_seek($qOne, 0);

Categories