display 0 to 23 hours table using php or mysql - php

I have a table in mysql that has time date and in military format ( 2014-01-22 16:10:02 )
caller_data
|ID | caller_id | call_time
| 1 | 123 | 2014-01-22 16:10:02
| 2 | 123 | 2014-01-22 16:30:02
| 3 | 123 | 2014-01-22 17:10:02
| 4 | 123 | 2014-01-22 18:05:45
on the range of their time like 16:10 and 16:30 . I group them using HOUR(), the result is 16. I will count it of how many times did the caller call on the range of that hour. so that would be 2.
My query:
SELECT caller_id,
HOUR(str_to_date(date_stamp, "%Y-%m-%d %H:%i:%s")) as hourly,
count(*) as total
from caller_data
group by hourly
order by hourly;
which the result should be:
caller_id | hourly | total
123 | 16 | 2
123 | 17 | 1
123 | 18 | 1
I want to display these 3 rows on a 0-23 . I've been trying to display this with php but it display 3 times when I created a for $i <= 23 ..
for($i=0;i<=23;$i++)
{
foreach ($rec as $row):
echo $row['hourly'];
echo $row['caller_id'];
echo $row['total'];
endforeach;
}
I dont know if it's possible to display this on mysql.. can someone show how to do it with php or mysql?
| hours | caller_id | total
| 0 | 123 | 0
| 1 | 123 | 0
| 2 | 123 | 0
| 3 | 123 | 0
| 4 | 123 | 0
| 5 | 123 | 0
| 6 | 123 | 0
| 7 | 123 | 0
| 8 | 123 | 0
| 9 | 123 | 0
| 10 | 123 | 0
| 11 | 123 | 0
| 12 | 123 | 0
| 13 | 123 | 0
| 14 | 123 | 0
| 15 | 123 | 0
| 16 | 123 | 2
| 17 | 123 | 1
| 18 | 123 | 1
| 19 | 123 | 0
| 20 | 123 | 0
| 21 | 123 | 0
| 22 | 123 | 0
| 23 | 123 | 0

You can do this in SQL with a left outer join. You just have to type in all the hours:
select caller_id, n.n as hourly, coalesce(total, 0) as total
from (select 1 as n union all select 2 union all select 3 union all select 4 union all
select 5 union all select 6 union all select 7 union all select 8 union all
select 9 union all select 10 union all select 11 union all select 12 union all
select 13 union all select 14 union all select 15 union all select 16 union all
select 17 union all select 18 union all select 19 union all select 20 union all
select 21 union all select 22 union all select 23 union all select 24
) n left outer join
(select caller_id, HOUR(str_to_date(date_stamp, "%Y-%m-%d %H:%i:%s")) as hourly,
count(*) as total
from caller_data
group by hourly
) rep
on n.n = rep.hourly
order by hourly;

Related

Get Highest amount , count of products / users

id | user_id | prd_id | amnt | dis
1 | 1 | 10 | 200 | 23
2 | 2 | 10 | 300 | 11
3 | 3 | 20 | 100 | 26
4 | 2 | 20 | 50 | 12
5 | 4 | 30 | 100 | 22
6 | 2 | 40 | 600 | 18
7 | 2 | 30 | 100 | 16
I want 2 result from above table :
First by prod_id as below
prd_id | user_id | cont | highestamt | disc
10 | 2 | 2 | 300 | 11
20 | 3 | 2 | 100 | 26
30 | 4 | 2 | 100 | 22
40 | 2 | 1 | 600 | 18
Second by user_id as below:
user_id | cont | bid on prd_id | winner on bid prod_id |
1 | 1 | 10 | - | -
2 | 4 | 10,20,30,40 | 10,40 |
3 | 1 | 20 | 20 |
4 | 1 | 30 | 30 |
UPDATE : ex: above : user_id = 2 has bid on product 10,20,30,40 ( bid on prd_id ) hence his bidding cont = 4 ...and out of which he is winner in 10,40 ( winner on bid prod_id ) ..WHY ONLY 10,40 and not 30 ...bcz user_id =4 has bid on prd=30 with amt =100 and user_id =2 with amt=100 ..but first bid was made by user=4 on prd=30 hence he is winner for prd=30 ( for same amt )
Tried below query for by prd_id but it giving me some wrong result.
SELECT `prd_id`, `user_id` , count('prd_id') as cont , max(`amnt`) as highestamt,disc
FROM `proddtails`
group by `prd_id` order by `prd_id`
above query result as below : ( user_id,disc not coming proper )
prd_id | user_id | cont | highestamt | disc
10 | 2 | 2 | 300 | 11
20 | 2 | 2 | 100 | 11
30 | 2 | 1 | 100 | 11
40 | 2 | 1 | 600 | 11
For second by user_id I am not getting what will be query.
Thanks
UPDATE :
THANKS FOR HARSHIL : http://www.sqlfiddle.com/#!9/5325a6/5/1
but after some more entry i found this bug : http://www.sqlfiddle.com/#!9/e04063/1 for second : for user_id but works well for prd_id (first query )
user_id cont bid_on_prd_id winner_on_bid_prod_id
1 1 10 (null)
2 4 10,20,40,30 10,40,30
3 1 20 20
4 1 30 30
but i want as below :
without null user_id
user_id cont bid_on_prd_id winner_on_bid_prod_id
2 4 10,20,30,40 10,40
3 1 20 20
4 1 30 30
with null user_id ( but in my wamp server i don't see null in winner_on_bid_prd_id for user_id =1 , i get value 10 instead of null )
user_id cont bid_on_prd_id winner_on_bid_prod_id
1 1 10 (null)
2 4 10,20,30,40 10,40
3 1 20 20
4 1 30 30
For prd_id:
select t1.prd_id,t1.user_id,
(select count(*) from tablename where prd_id = t1.prd_id)as cont,
t1.amnt as highststatment,
t1.dis as disc
from tablename t1
where (t1.prd_id,t1.amnt) in
(select prd_id, max(amnt) from tablename group by prd_id)
group by t1.prd_id;
For usr_id:
select t1.user_id,
count(*) as cont,
Group_concat(t1.prd_id separator ',') as bid_on_prd_id,
(select Group_concat(distinct t2.prd_id separator ',')
from tablename t2
where t2.user_id = t1.user_id
and (t2.id) in
(select min(id) from tablename
where (prd_id,amnt) in
(select prd_id,max(amnt) from tablename group by prd_id)
group by prd_id
)
) as winner_on_bid_prod_id
from tablename t1
group by t1.user_id
having winner_on_bid_prod_id IS NOT NULL;
Click here for UPDATED DEMO

mysql function to divided a sum value of a coulmn and

I have a Table call payments,
paymentid stuid stu_name fullamount pay_comp
1 1234 Jhon 2600 Feb
2 1212 Silva 1300 Jan
3 1234 Jhon 1300 March
4 1212 Silva 3900 April
5 3333 Perera 15600 Dec
Here a student can pay for the whole year,for several month or for a single month,Payments are done by 1300,
For a example if "Silva" paid 1300 for the first time he will be paying for Jan.
If he doing a another 1300 payment,Then it will be marked as for next month,Which is "Feb".If someone complete 15600 payment it will be saved as "Dec".
The problem is that when calculating Total Amount for the Jan it must consider that 1300 from Dec payment.
What i want is to calculate total Amount for each month.The problem is "Pay_Com" column is insert records as above.It can be for the whole year or for a single month.Is there any way around this.
I tried different methods,can i use sum of full amount divided by 1300 to calculate full amount for each month.Can anyone suggest me a soultion or a sql Function.
even tried IF and Sum with cases..
SELECT
CASE
WHEN round(sum(full_amount)/1300) = 1 THEN 1
ELSE 0
END AS 'Jan',
CASE
WHEN round(sum(full_amount)/1300) = 2 THEN 2
ELSE 0
END AS 'Feb',
CASE
WHEN round(sum(full_amount)/1300) = 3 THEN 3
ELSE 0
END AS 'March',
Can anyone suggest me a Solution.
Thanks In Advance.
I am Looking for a Something Like.
Month Full_PaymentsRecived
Jan 20000
Feb 3900
.... ....
Dec 2600
You know that every stuid is due 1300 every month, you can calculate how much has been paid by every stuid. From this you can apportion forwards from month one decrementing the paid amount as you go.
SELECT Y.MM,
SUM(Y.DUEAMT) PAYMENTSEXPECTED,
SUM(Y.PAID) PAYMENTSRECEIVED,
(SUM(Y.PAID) / SUM(Y.DUEAMT)) * 100 RATIO_PAID_DUE,
SUM(CASE WHEN Y.PAID > 0 THEN 1 ELSE 0 END) NUMBER_OF_PAYMENTS_RECEIVED,
SUM(CASE WHEN Y.PAID = 0 THEN 1 ELSE 0 END) NUMBER_OF_PAYMENTS_MISSED,
SUM(CASE WHEN Y.PAID < Y.DUEAMT AND Y.PAID > 0 THEN 1 ELSE 0 END) NUMBER_OF_UNDERPAYMENTS
FROM
(
SELECT X.STUID,X.MM,
X.DUEAMT,
#IF(X.STUID <> #P, #TOTALPAID:=(SELECT SUM(FULLAMOUNT) FROM T WHERE T.STUID = X.STUID),0) TOTALPAID,
IF(X.STUID <> #P, #FULLAMOUNT:=(SELECT SUM(FULLAMOUNT) FROM T WHERE T.STUID = X.STUID)
#- X.DUEAMT
,
#FULLAMOUNT:=#FULLAMOUNT - X.DUEAMT) EXHAUST,
CASE WHEN #FULLAMOUNT >= X.DUEAMT THEN X.DUEAMT
WHEN #FULLAMOUNT < 0 THEN 0
ELSE #FULLAMOUNT
END AS PAID,
#P:=X.STUID
FROM
(
SELECT DISTINCT T.STUID , 1300 AS DUEAMT, S.MM
FROM T,
(
SELECT 1 AS MM UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION
SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION
SELECT 9 UNION SELECT 10 UNION SELECT 11 UNION SELECT 12
) S
) X , (SELECT #TOTALPAID:=0,#FULLAMOUNT:=0,#P:=0) FA
ORDER BY X.STUID,X.MM
) Y
GROUP BY Y.MM
The sub query S generates a due amount for each month for each student
The Sub query X then works out and amount paid for each month for each student
The sub query Y then aggregates to get a result (I have added some addition analysis not required in your question).
So given
MariaDB [sandbox]> select * from t;
+-----------+-------+----------+------------+----------+
| paymentid | stuid | stu_name | fullamount | pay_comp |
+-----------+-------+----------+------------+----------+
| 1 | 1234 | Jhon | 2600 | Feb |
| 2 | 1212 | Silva | 1000 | Jan |
| 3 | 1234 | Jhon | 1300 | Mar |
| 4 | 1212 | Silva | 3900 | Apr |
| 5 | 3333 | Perera | 15600 | Dec |
+-----------+-------+----------+------------+----------+
5 rows in set (0.02 sec)
Result
MM | PAYMENTSEXPECTED | PAYMENTSRECEIVED | RATIO_PAID_DUE | NUMBER_OF_PAYMENTS_RECEIVED | NUMBER_OF_PAYMENTS_MISSED | NUMBER_OF_UNDERPAYMENTS |
+----+------------------+------------------+-------------------+-----------------------------+---------------------------+-------------------------+
| 1 | 3900 | 3900 | 100 | 3 | 0 | 0 |
| 2 | 3900 | 3900 | 100 | 3 | 0 | 0 |
| 3 | 3900 | 3900 | 100 | 3 | 0 | 0 |
| 4 | 3900 | 2300 | 58.97435897435898 | 2 | 1 | 1 |
| 5 | 3900 | 1300 | 33.33333333333333 | 1 | 2 | 0 |
| 6 | 3900 | 1300 | 33.33333333333333 | 1 | 2 | 0 |
| 7 | 3900 | 1300 | 33.33333333333333 | 1 | 2 | 0 |
| 8 | 3900 | 1300 | 33.33333333333333 | 1 | 2 | 0 |
| 9 | 3900 | 1300 | 33.33333333333333 | 1 | 2 | 0 |
| 10 | 3900 | 1300 | 33.33333333333333 | 1 | 2 | 0 |
| 11 | 3900 | 1300 | 33.33333333333333 | 1 | 2 | 0 |
| 12 | 3900 | 1300 | 33.33333333333333 | 1 | 2 | 0 |
+----+------------------+------------------+-------------------+-----------------------------+---------------------------+-------------------------+
12 rows in set (0.04 sec)

SQL Inner join and Limit records

This is a simplification table structure that i have.
I have two tables.
TABLE 1
ID PTS PID TID
----------------------------------------
1 3 1 22
2 10 1 22
3 5 1 22
4 1 2 58
5 0 2 58
7 0 3 47
8 5 3 47
15 5 4 51
15 3 4 51
9 7 3 6
10 0 1 8
11 2 1 8
12 4 5 1
13 1 6 9
14 2 5 12
15 5 4 61
15 6 4 61
15 2 4 61
16 0 7 100
ect. ect. ect. ect.
TABLE 2
NAME PID
-------------------
Jhon 1
Peter 2
Lisa 3
Doe 4
Joey 5
Mike 6
Debby 7
ect. ect.
Now i need to select the latest two PTS from each TID and match them whit PID row on table 2. and calculate the Average.
THE DESIRED OUTCOME
NAME AVG
-------------------
Jhon 4,25
Peter 1,00
Lisa 6,00
Doe 4,00
Joey 3,00
Mike 1,00
Debby 0,00
ect. ect.
Clarification: the PID row are relational. Multiple TIDs can have the same PID and TIDs can have multiple PTS. I am using PDO socket.
At the time my query is:
$query = $db->prepare("SELECT IFNULL(AVG(pts), 0) AS P, TA1.PID AS TA1PID, name AS N FROM ".
"table1 TA1 LEFT JOIN table2 TA2 ON TA1.PID = TA2.PID ".
"GROUP BY name, TA2.PID ".
"ORDER BY TA1.id DESC");
But this calculates all the points(PTS) from TID. but i would like to only calculate the Two latest points(PTS) per TID. I have tried different queries the whole day but i cant figure it out. I am pretty new to SQL I managed to get one example working but with pure PHP and its not pretty :D
sqlFiddle: LINK
The problem is that it calculates all the TID points in Average. It only should calculate the two last entries per TID
I hope this is a clear question. I have tried my best to explain my problem. If any questions please ask. I have read other similar problems than mine here on Stackoverflow but i could not modify them to work for me.
You can select only the most recent 2 rows from the first table using this query
select t1.id, t1.pts, t1.pid, t1.tid
from table1 t1
join table1 t2 on t2.id >= t1.id and t1.tid = t2.tid
group by t1.id
having count(*) <= 2
and plug it into your original query instead of table 1
SELECT IFNULL(AVG(pts), 0) AS AVG, TA1.PID AS
Table1_ID, name AS Name FROM
(
select t1.id, t1.pts, t1.pid, t1.tid
from table1 t1
join table1 t2 on t2.id >= t1.id and t1.tid = t2.tid
group by t1.id
having count(*) <= 2
)
TA1 LEFT JOIN table2 TA2 ON TA1.PID = TA2.PID
GROUP BY name, TA2.PID
ORDER BY TA1.id DESC
Group Per N are pretty easy in Most DBs. Just use ROW_NUMBER. Unfortunately MySQL doesn't have them so we must simulate it
SELECT name,
Avg(PTS)
FROM
(
SELECT *,
CASE
WHEN #previousPID IS NULL
OR #previousTID IS NULL
OR ( #previousPID = ORDERED.pid
AND #previousTID = ORDERED.tid )
THEN #rownum := #rownum + 1
ELSE #rownum := 1
end rn,
#previousPID := ORDERED.pid ,
#previousTID := ORDERED.tid
FROM (SELECT t2.name,
t2.pid,
t1.id,
t1.tid ,
t1.Pts
FROM table2 t2
INNER JOIN table1 t1
ON T2.pid = t1.pid
ORDER BY t1.pid,
t1.tid,
t1.id DESC)ORDERED,
(SELECT #rownum := 0,
#previousPID := NULL,
#previousTID := NULL) t) CTE
WHERE CTE.rn <= 2
GROUP BY name
Which has the following Results
| NAME | AVG(PTS) |
|-----------|----------|
| Doe | 4 |
| Jhon | 4.25 |
| Joey | 3 |
| Lisa | 4 |
| Mike | 1 |
| No points | 0 |
| Peter | 0.5 |
DEMO
Looking at the intermediate results may help to understand how the CASE statements generate the rownumbers
| NAME | PID | ID | TID | PTS | #ROWNUM := 0 | #PREVIOUSPID := NULL | #PREVIOUSTID := NULL | RN | #PREVIOUSPID := ORDERED.PID | #PREVIOUSTID := ORDERED.TID |
|-----------|-----|----|-----|-----|--------------|----------------------|----------------------|----|-----------------------------|-----------------------------|
| Jhon | 1 | 3 | 22 | 5 | 0 | (null) | (null) | 1 | 1 | 22 |
| Jhon | 1 | 2 | 22 | 10 | 0 | (null) | (null) | 2 | 1 | 22 |
| Jhon | 1 | 1 | 22 | 3 | 0 | (null) | (null) | 3 | 1 | 22 |
| Jhon | 1 | 12 | 8 | 2 | 0 | (null) | (null) | 1 | 1 | 8 |
| Jhon | 1 | 11 | 8 | 0 | 0 | (null) | (null) | 2 | 1 | 8 |
| Peter | 2 | 5 | 58 | 0 | 0 | (null) | (null) | 1 | 2 | 58 |
| Peter | 2 | 4 | 58 | 1 | 0 | (null) | (null) | 2 | 2 | 58 |
| Lisa | 3 | 7 | 47 | 5 | 0 | (null) | (null) | 1 | 3 | 47 |
| Lisa | 3 | 6 | 47 | 0 | 0 | (null) | (null) | 2 | 3 | 47 |
| Lisa | 3 | 10 | 6 | 7 | 0 | (null) | (null) | 1 | 3 | 6 |
| Doe | 4 | 9 | 51 | 3 | 0 | (null) | (null) | 1 | 4 | 51 |
| Doe | 4 | 8 | 51 | 5 | 0 | (null) | (null) | 2 | 4 | 51 |
| Doe | 4 | 19 | 61 | 2 | 0 | (null) | (null) | 1 | 4 | 61 |
| Doe | 4 | 17 | 61 | 6 | 0 | (null) | (null) | 2 | 4 | 61 |
| Doe | 4 | 16 | 61 | 5 | 0 | (null) | (null) | 3 | 4 | 61 |
| Joey | 5 | 13 | 1 | 4 | 0 | (null) | (null) | 1 | 5 | 1 |
| Joey | 5 | 15 | 12 | 2 | 0 | (null) | (null) | 1 | 5 | 12 |
| Mike | 6 | 14 | 9 | 1 | 0 | (null) | (null) | 1 | 6 | 9 |
| No points | 7 | 18 | 100 | 0 | 0 | (null) | (null) | 1 | 7 | 100 |

Optimize MySQL query to find rank of a user for differnet tests in single query

I am using the query to find the rank of a user in a given test id, and this gives me rank for just one test at a time and I have to use foreach to get the test rank of all the test.
SELECT * , t.UserRank
FROM (
SELECT * , (
#rownum := #rownum +1
)UserRank
FROM User_Date_Table, (
SELECT #rownum :=0
)t
WHERE my_test_id = '$test_id'
ORDER BY test_score DESC
)t
WHERE user_id = '$my_user_id'
Can a query be generated which can give me user rank for all the test taken by user in single query as this will reduced the db hitting multiple times.
I have to find the all the ranks of user with Test_Type_Id = $my_test_type_id(say), joining a.id with b.my_test_id for a user with user_id = $my_user_id(say)
TABLE STRUCTURE
My_Test_Table (a)
id | name | Test_Type_Id
----------------------------------------------
1 | name_1 | 1
2 | name_2 | 1
3 | name_3 | 2
4 | name_4 | 1
5 | name_5 | 1
6 | name_6 | 2
7 | name_7 | 1
8 | name_8 | 2
9 | name_9 | 1
User_Date_Table (b)
id | my_test_id | user_id | test_score
---------------------------------------------------------
1 | 1 | 32 | 34
2 | 1 | 2 | 345
3 | 2 | 4 | 654
4 | 1 | 76 | 87
5 | 3 | 23 | 453
6 | 2 | 5 | 45
7 | 1 | 43 | 22
8 | 2 | 7 | 987
9 | 2 | 32 | 45
10 | 1 | 1 | 12
11 | 1 | 9 | 35
12 | 3 | 67 | 765
13 | 1 | 88 | 23
14 | 2 | 34 | 76
15 | 3 | 1 | 765
16 | 2 | 54 | 45
17 | 1 | 10 | 87
18 | 1 | 23 | 3
19 | 3 | 44 | 345
20 | 1 | 55 | 232
21 | 2 | 28 | 234
22 | 3 | 32 | 231
Simplest is probably to just remove the user variable for ranking and just do it using a subquery;
SELECT *, (SELECT COUNT(*)+1
FROM User_Date_Table b
WHERE a.my_test_id = b.my_test_id
AND a.test_score < b.test_score) userrank
FROM User_Date_Table a
WHERE user_id = '1';
An SQLfiddle to test with.
SELECT * , t.UserRank
FROM (
SELECT * , #rownum :=if(#user!=user_id,0, #rownum +1),#user:=user_id UserRank
FROM User_Date_Table , (SELECT #rownum :=0,#user :=-1) t
ORDER BY my_test_id ,test_score DESC
)t
WHERE user_id = '$my_user_id'
We introducean additional variable #user to reset #rownum on user_id change

how to get count total occurance from different tables in Mysql

I have three different tables for 3 different activities. The common field is user_id.
Performance:
id | user_id | date | mark
1 | 123 | xx | 20
2 | 456 | xx | 10
3 | 789 | xx | 5
4 | 123 | xx | 10
5 | 456 | xx | 10
6 | 789 | xx | 5
Internal Activities:
id | user_id | date | mark
1 | 123 | xx | 20
2 | 456 | xx | 10
3 | 789 | xx | 5
4 | 123 | xx | 10
5 | 456 | xx | 10
6 | 789 | xx | 5
Other Activities :
id | user_id | date | mark
1 | 123 | xx | 20
2 | 456 | xx | 10
3 | 789 | xx | 5
4 | 123 | xx | 10
5 | 456 | xx | 10
6 | 789 | xx | 5
How to fetch each user marks in all the 3 tables for and sort it in DESC. result should be like
id | user_id | mark
1 | 123 | 90
2 | 456 | 60
3 | 789 | 30
Thanks in advance
SELECT tmp.ID,tmp.USER_ID,tmp.SUM(mark)
FROM
(select * from Performance
union all
select * from Internal_Activities
union all
select * from Other_Activities
) as tmp
group by tmp.USER_ID
Note :- Why are you keeping 3 separate table with same schema ,cant you make it one ?
Try this:
SELECT p.id, p.user_id, SUM(p.mark) FROM Performance p
LEFT JOIN Internal Activities ia ON p.id=ia.id
LEFT JOIN Other Activities oa ON ia.id=oa.id
GROUP BY p.user_id;
SELECT
p.id
,p.user_id
,#performance:=p.mark AS performance
,#other_activities:=oa.mark AS other_activities
,#internal_activities:=ia.mark AS internal_activities
,#total_mark:=#performance+#other_activities+#internal_activities AS total_mark
FROM
table1 p
LEFT JOIN table2 ia
USING(user_id)
LEFT JOIN table2 oa
USING(user_id)

Categories