How to Sum amount of same role records? - php

I want to get amount of same role in one sum. When I fetch a records of agent details introduced by some agent (11150000001). It will return lot of agents records with different role(1000,2000,3000,4000,5000,6000).
From that I need to get the agents business amount total. Now I'm getting it. But If there is some agent in same role I want to get that same role agent's amount in single amount, but I'm getting separately.
//get all employee under one employee
$rank1=''; $rank2='';$rank3='';$rank4='';$rank5='';$rank6='';
$get_employee="SELECT emp_code,intro_code FROM emp_details WHERE intro_code='".$emp_code."'";
$exe_employee=mysql_query($get_employee);
while($fetch_emp=mysql_fetch_assoc($exe_employee))
{
$total_amount1=0;
$role='';
$employee_code=$fetch_emp['emp_code'];
//echo $employee_code."<br>";
$get_premium="SELECT emp_code,user_role,premium_amount FROM business_details WHERE emp_code='".$employee_code."'";
//echo $get_premium."<br>";
$exe_premium=mysql_query($get_premium);
while($fetch_amount=mysql_fetch_array($exe_premium))
{
$total_amount1 +=$fetch_amount['premium_amount'];
$role=$fetch_amount['user_role'];
}
}
echo $role."-".$total_amount1."<br>";
// Role-Amount
// 5000-75000
// 5000-105000
//3000-15000
In the above image I'm getting 10,500 in rank 5, but I want to get the 75000+10500 in rank 5 column.
Below is my table structure:

The entire block of code than be replaced by a single SQL query. You want to create a pivot table.
Lets start by a relatively simple query that fetches the total premium_amount of all the employee-role combinations:
SELECT emp_code,
user_role,
SUM(premium_amount) AS total_amount
FROM business_details
GROUP BY emp_code, user_role;
This would yield something like this:
emp_code | user_role | total_amount
-----------------------------------
15040000001 | 3000 | 15000
15040000001 | 5000 | 180000
11130000001 | 4000 | 30000
11130000001 | 1000 | 5000
This already contains all the information you want in your table, but not in the correct layout. Instead of using PHP to reformat this into the rows/columns you want for your table, SQL can do it for us.
Instead of grouping by user_role, we're going to specify the different values user_role can take as different columns:
SELECT emp_code,
SUM(CASE WHEN user_role=1000 THEN premium_amount ELSE 0 END) AS rank1,
SUM(CASE WHEN user_role=2000 THEN premium_amount ELSE 0 END) AS rank2,
SUM(CASE WHEN user_role=3000 THEN premium_amount ELSE 0 END) AS rank3,
SUM(CASE WHEN user_role=4000 THEN premium_amount ELSE 0 END) AS rank4,
SUM(CASE WHEN user_role=5000 THEN premium_amount ELSE 0 END) AS rank5,
SUM(CASE WHEN user_role=5000 THEN premium_amount ELSE 0 END) AS rank6
FROM business_details
GROUP BY emp_code;
The result would be:
emp_code | rank1 | rank2 | rank3 | rank4 | rank5 | rank6
------------------------------------------------------------
15040000001 | 0 | 0 | 15000 | 0 | 180000 | 0
11130000001 | 5000 | 0 | 0 | 30000 | 0 | 0
Bonus advise
The PHP code you've posted contains a glaring security flaw that leaves your database (or probably your entire system) wide open to anyone. SQL injection is not fun to have in your web application! I've written about it in a previous answer.

Try this...
$get_premium="SELECT emp_code,user_role,premium_amount,SUM(premium_amount) FROM business_details WHERE emp_code='".$employee_code."' group by user_role" ;

Related

Joining a calendar table to a sales table to get total sales for every day in a specified range

I have a 'sales' table called phpbb_sold which records each 'sale' as a row.
I am able to use a WHERE clause with the uitemid field to select one particular item in the sales records, as seen below:
SELECT uitemid, locktime, migrated_sold FROM phpbb_sold WHERE uitemid=342;
+---------+------------+---------------+
| uitemid | locktime | migrated_sold |
+---------+------------+---------------+
| 342 | 1632523854 | 1 |
| 342 | 1634239244 | 1 |
| 342 | 1634240072 | 1 |
| 342 | 1636367271 | 1 |
+---------+------------+---------------+
uitemid = number that identifies this as a sale of X item. locktime = UNIX timestamp that shows the datetime that the item was sold. migrated_sold = the quantity of the item sold. So this is nice, I have a table that keeps a record of each sale as it happens.
What I want to achieve though, is a record of the total number of sales of this item type, for each day in a 6 month period spanning back from the current date, and including each day regardless of whether a sale was made or not. So the desired output of my query would be:
SELECT (the query I want goes here) and returns the following rows...;
+------------+------------+
| caldate | sold_total |
+------------+------------+
| 2021-09-23 | 2 |
| 2021-09-24 | 0 |
| 2021-09-25 | 1 |
| 2021-09-26 | 0 |
| 2021-09-27 | 0 |
| 2021-09-28 | 1 |
+------------+------------+
Note that each day is included as a row in the results, even where the sales total for that day is 0. I read that to do this, I would be required to create a calendar table with one column and all the days I want as rows, so I went ahead and did that:
SELECT caldate FROM phpbb_calendar;
+------------+
| caldate |
+------------+
| 2021-09-23 |
| 2021-09-24 |
| 2021-09-25 |
| 2021-09-26 |
| 2021-09-27 |
| 2021-09-28 |
+------------+
Now all that remains is for me to make the query. I need to somehow return all the rows from the phpbb_calendar table, joining the data from sum() (?) of the total migrated_sold for those days where exists, and a 0 where no sales took place.
I anticipated some issues with the UNIX timestamp, but it's okay because I am able to get caldate and locktime fields to be the same format by using from_unixtime(locktime, '%Y-%m-%d'), so both dates will be in the YYYY-MM-DD format for comparison.
Please could someone help me with this. I've gotten so close every time but it seems that everyone else's request is only slightly different from mine, so existing questions and answers have not been able to satisfy my requirements.
End goal is to use a JS chart library (AnyChart) to show a line graph of the number of sales of the item over time. But to get there, I first need to provide it with the query necessary for it to display that data.
Thanks
Update
Using this query:
SELECT c.caldate, u.uitemid, sum(v.migrated_sold) as total_sales
from phpbb_calendar c cross join
(select distinct uitemid from phpbb_sold) u left join
phpbb_sold v
on c.caldate = from_unixtime(v.locktime, '%Y-%m-%d') WHERE u.uitemid = 39 and c.caldate <= curdate() GROUP BY c.caldate ORDER BY c.caldate;
Returns:
But as you can see, it's just tallying up the total number of sales ever made or something - its clearly incrementing in a way I don't understand.
I don't want it to do that - I want it to count the number of total sales on each day individually. The results should look like this:
So that what is returned is basically a 'histogram' of sales, if any occurred, including 'empty' days where there were no sales (so these empty days must still be returned as rows).
SELECT c.caldate, u.uitemid, COALESCE(SUM(v.migrated_sold), 0) AS total_sales
FROM phpbb_calendar c
CROSS JOIN (SELECT DISTINCT uitemid FROM phpbb_sold WHERE uitemid = 37) u
LEFT JOIN phpbb_sold v
ON v.locktime BETWEEN UNIX_TIMESTAMP(TIMESTAMP(c.caldate)) AND UNIX_TIMESTAMP(TIMESTAMP(c.caldate, '23:59:59'))
AND u.uitemid = v.uitemid
WHERE c.caldate BETWEEN CURDATE() - INTERVAL 6 MONTH AND CURDATE()
GROUP BY c.caldate, u.uitemid
ORDER BY c.caldate;
N.B. I have changed your join to use the unix_timestamp as it should be more efficient and it can use any existing index on locktime
check this out:
select id, d, sum(s) from (
select U.id, d, 0 s from (
select adddate(current_date(),-rows.r) d from (
select (#row_number := #row_number + 1) r
from information_schema.columns,
(SELECT #row_number := 0) AS x
limit 200
) rows
) dates,
(SELECT distinct uitemid id FROM `phpbb_sold`) U
where d > adddate(current_date(), interval -6 month)
union
select uitemid, date(from_unixtime(locktime)),sum(migrated_sold)
from `phpbb_sold`
group by uitemid, date(from_unixtime(locktime))
) sales_union
group by id, d
order by id, d;
see dbfiddle
no need for calendar table

SQL Statement to Group results by two rows to create a timetable

I currently have a database table which records the bookings of jobs
and there are 8 timeslots available
+-----------+
|tbl_booking|
+-----------+
|room_id |
|date |
|timeslot |
|booking |
+-----------+
sample data
+-----------+----------+-----------+
|room_id | date | timeslot |
+-----------+----------+-----------+
|1 |2018-01-01| 1 |
|1 |2018-01-01| 2 |
|1 |2018-01-01| 4 |
|2 |2018-01-01| 1 |
+-----------+----------+-----------+
intended outcome - when statement filters for bookings on 2018-01-01
+-----------+----------+-----------+----------+-----------+
|room |timeslot1 | timeslot2 |timeslot3 | timeslot4 |
+-----------+----------+-----------+----------+-----------+
|1 | X | X | | X |
|2 | X | | | |
+-----------+----------+-----------+----------+-----------+
i started off with this statement:
SELECT * from tbl_booking WHERE date = '2018-01-01' GROUP BY room_id
and this would return results to see the results grouped by rooms.
I would like to know where i should go from here to also have the results display it's timeslots that are shown in a table displaying the booking status of eacah room's timeslot in the day?
Should there be an SQL statement that i should be using or am I on the wrong track completely?
Any help would be appreciated.
Thank you!
What you want to do with the data isn't nice to do and if you have a fixed number of time slots then you can hardcode the columns like this:
SELECT room_id,
SUM(CASE WHEN timeslot = 1 then 1 else 0 END) AS Timeslot1,
SUM(CASE WHEN timeslot = 2 then 1 else 0 END) AS Timeslot2,
SUM(CASE WHEN timeslot = 3 then 1 else 0 END) AS Timeslot3,
SUM(CASE WHEN timeslot = 4 then 1 else 0 END) AS Timeslot4
FROM tbl_booking
GROUP BY room_id
(see SQL Fiddle)
You could use MAX if you just want to see if at least 1 booking exist
SQL to include remark, you can trick it to select the remark through a group by with MAX
SELECT room_id,
SUM(CASE WHEN timeslot = 1 then 1 else 0 END) AS Timeslot1,
MAX(CASE WHEN timeslot = 1 THEN remark ELSE '' END) AS Timeslot1Remark,
SUM(CASE WHEN timeslot = 2 then 1 else 0 END) AS Timeslot2,
MAX(CASE WHEN timeslot = 2 THEN remark ELSE '' END) AS Timeslot2Remark,
SUM(CASE WHEN timeslot = 3 then 1 else 0 END) AS Timeslot3,
MAX(CASE WHEN timeslot = 3 THEN remark ELSE '' END) AS Timeslot3Remark,
SUM(CASE WHEN timeslot = 4 then 1 else 0 END) AS Timeslot4,
MAX(CASE WHEN timeslot = 4 THEN remark ELSE '' END) AS Timeslot4Remark
FROM tbl_booking
GROUP BY room_id
your extended SQL Fiddle. This won't work for multiple dates only 1 selected date
If you are looking for dynamic solutions then you must need to use pivot table.
Select * from
(select * from yourtable) as
Temptable
Pivot (
Count(room)
For timeslot
In (list of timeslot))
As tempSlot
For more information check this link MySQL pivot table

Cannot figure out SQL SUM() with a WHERE

I'm trying to get a result from SQL database, and I want it to get a ratio and sort it by that ratio. That is number of rows where the value is yes and costumerid is the same, divided by the total number of rows with the costumerid, and ORDER BY that ratio. This is what I have at the moment:
$sqlsortby = "SELECT DISTINCT q2, q14,
(SUM(WHERE costumerid='$costumerid' AND option1='yes') /
SUM(WHERE costumerid='$costumerid')) AS costumerratio
FROM costumers
WHERE q14='successful' AND ordernum='$ordernumsession'
ORDER BY costumerratio";
Thanks :)
-------------------------------------------------------------
| q2 | costumerid | option1 | ordernum | q14 |
-------------------------------------------------------------
| Bob | 1 | yes | 001 | successful|
| Bob | 1 | no | 002 | successful|
-------------------------------------------------------------
In MySQL, I think this is the simplest way to do what you want:
SELECT q2, q14, AVG(option1 = 'yes') as costumerratio
FROM costumers
WHERE q14 = 'successful' AND ordernum = '$ordernumsession' AND
costumerid = '$costumerid'
GROUP BY q2, q14
ORDER BY costumerratio;
You can do essentially the same thing in other databases, but it requires CASE.
Note that this assumes that you want rows where customerid = $costumerid.
Using SUM() without GROUP BY as you currently have probably is not what you want, because it will return just a single record in the result set. More typically, we use SUM() with GROUP BY. Here is my guess as to what you want:
SELECT t.*
FROM
(
SELECT q2, q14,
SUM(CASE WHEN costumerid='$costumerid' AND option1='yes'
THEN 1 ELSE 0 END) /
SUM(CASE WHEN costumerid='$costumerid' THEN 1 ELSE 0 END) AS costumerratio
FROM costumers
WHERE q14='successful' AND
ordernum='$ordernumsession'
GROUP BY q2, q14
) t
ORDER BY t.costumerratio
Also note that the code you were using inside SUM() to aggregate was broken. Instead, I have replaced it with CASE expressions.

Mysql users compare to itself

I'm trying to create a overview Who owe's who on call hours.
below the table i have.
so user 2 has done 9 hours for user 1. but user 1 has done 3 hours for user 2 so the total owing from user 1 is 6 hours. and user 2 is owing user 3, 2 on call hours. how can i make a cross reference table from all users in Mysql?
First, this is not a natural thing to do in SQL. But it is possible. To make a cross-reference table, you need to generate the rows and then fill the columns:
select user_id_a,
sum(case when user_id_b = 1 then hours_oncall else 0 end) as user_1,
sum(case when user_id_b = 2 then hours_oncall else 0 end) as user_2,
sum(case when user_id_b = 3 then hours_oncall else 0 end) as user_3
from ((select user_id_a from t
) union
(select user_id_b from t
)
) u left join
t
on t.user_id_a = u.user_id_a
group by u.user_id_a;
In plain SQL you can't have a dynamic number of columns that adjusts to the number of users, though in your code you could generate SQL that does that. But I think you are better off just getting rows showing who owes whom how many hours and transforming the data like a pivot table in your code.
To get the basic data, assuming your table is called hours_oncall:
select ower,owed,sum(hours_oncall) hours
from (
select user_id_a ower,user_id_b owed,hours_oncall from hours_oncall
union all
select user_id_b,user_id_a,-hours_oncall from hours_oncall
) hours_oncall_union
group by 1,2
having hours>0;
which for your sample data, returns:
+------+------+-------+
| ower | owed | hours |
+------+------+-------+
| 1 | 2 | 6 |
| 2 | 3 | 2 |
+------+------+-------+

Separate Data into Days of the week mysql

Good day,
I am currently making a sales tracking report where the user pick a date range then the table should display the result.
for now I have this query that counts how many items are sold
select x_transaction_details.xitem,
SUM(x_transaction_details.qty) as totalNumberSold,
count(x_transaction_details.xitem) as occurence,
x_transaction_details.cost,
i_inventory.xitem,
x_transaction_details.date_at as transDate
from x_transaction_details
left join i_inventory on x_transaction_details.xitem = i_inventory.xid
where (x_transaction_details.date_at BETWEEN '2015-08-13 08:34:12' AND '2015-09-14 08:34:12')
GROUP BY x_transaction_details.xitem
ORDER BY occurence DESC
this query displays
|itemName| totalNumberSold | occurence | date
|item 1 | 23 pcs | 2 |
|item 2 | 18 pcs | 6 |
|item 3 | 203 pcs | 18 |
etc..
Now I want to know the breakdown of sales per day so I tried
select x_transaction_details.xitem,
SUM(x_transaction_details.qty) as sold,
count(x_transaction_details.xitem) as occurence,
x_transaction_details.cost,
i_inventory.xitem,
x_transaction_details.date_at as transDate
SUM(CASE WHEN date_at = DAYOFWEEK(1) THEN
count(x_transaction_details.xitem) END) as Sunday
from x_transaction_details
left join i_inventory on x_transaction_details.xitem = i_inventory.xid
where (x_transaction_details.date_at BETWEEN '2015-08-13 08:34:12' AND '2015-09-14 08:34:12')
GROUP BY x_transaction_details.xitem
ORDER BY occurence DESC
But its generating an error instead. I want to create a more detailed table
|itemName|Mon|Tue|Wed|Thur|Fri|Sat|Sun| totalNumberSold | occurence | date
|item 1 | 10| 0| 0 | 13 | 0 |0 |0 | 23 pcs | 2 |
|item 2 | 1 | 3| 12| 0 | 16|0 |0 | 32 pcs | 6 |
|item 3 | 0 | 6| 1 | 13 | 8 |7 |1 | 36 pcs | 12 |
etc..
Thanks for the tips, I can make this table using php (hard-way) too but I guess its doable using sql query as well. Have a good day ahead.
You are missing a comma and nesting aggregation functions. I think you want:
select i.xid, SUM(td.qty) as sold, count(td.xitem) as occurrence,
avg(td.cost) as avg_cost, i.xitem,
SUM(case when DAYOFWEEK(td.date_at) = 1 then td.qty else 0 end) as Sunday
from i_inventory i join
x_transaction_details td
on td.xitem = i.xid
where td.date_at BETWEEN '2015-08-13 08:34:12' AND '2015-09-14 08:34:12'
GROUP BY i.xid
ORDER BY occurrence DESC;
Notes:
"occurrence" has two r's.
Table aliases make the query easier to write and to read.
You can't nest aggregation functions.
You shouldn't include date_at in the select list because the value is not unique for each row.
The left join is either backwards (inventory should go first) or should be an inner join. In a properly formed database, you should not have items in the transaction table that are not in the inventory table (I don't think).
The actual code (might be helpful for anyone)
select x_transaction_details.xitem, count(x_transaction_details.xitem) as occurrence, i_inventory.xitem,
SUM(case when DAYOFWEEK(x_transaction_details.date_at) = 1 then x_transaction_details.qty else 0 end) as Sun,
SUM(case when DAYOFWEEK(x_transaction_details.date_at) = 2 then x_transaction_details.qty else 0 end) as Mom,
SUM(case when DAYOFWEEK(x_transaction_details.date_at) = 3 then x_transaction_details.qty else 0 end) as tue,
SUM(case when DAYOFWEEK(x_transaction_details.date_at) = 4 then x_transaction_details.qty else 0 end) as wed,
SUM(case when DAYOFWEEK(x_transaction_details.date_at) = 5 then x_transaction_details.qty else 0 end) as thur,
SUM(case when DAYOFWEEK(x_transaction_details.date_at) = 6 then x_transaction_details.qty else 0 end) as fri,
SUM(case when DAYOFWEEK(x_transaction_details.date_at) = 7 then x_transaction_details.qty else 0 end) as sat,
SUM(x_transaction_details.qty) as totalNumberSold
from x_transaction_details
left join i_inventory on x_transaction_details.xitem = i_inventory.xid
where (x_transaction_details.date_at BETWEEN '2015-08-13 08:34:12' AND '2015-09-14 08:34:12')
GROUP BY x_transaction_details.xitem
ORDER BY occurrence DESC
I did not used table aliases though :)

Categories