I have created a database of kittens where I need to use the following formula. In this regard I have two tables: birth and disposal.
Birth table contains id, dob, owner, date of purchase
disposal table contains id, date of disposal (dodisposal), cause of death, sold, treatment
I am now trying use a formula for the two table using the following MySQL query but it is not working.
Select birth.owner, (((select count(disposal.id) from disposal WHERE
dodisposal BETWEEN DATE_SUB(NOW(), INTERVAL 600 DAY) AND NOW()) /
(select count(birth.id) from birth where birth.id not in
(select disposal.id from disposal)
)
) * 100)
from birth left join disposal on
disposal.brandnumber = birth.id group by birth.owner
but I keep getting same results for all owners:
ie
rita : 79.6
sunita : 79.6
Smith : 79.6
The result I am expecting should be through the following formula:
Number of deaths in the current year / total number of live cats * 100
I found a solution to this problem by making two separate views and then their results using a MySQL query.
create view cats as select id, count(disposal.id) from disposal WHERE
dodisposal BETWEEN DATE_SUB(NOW(), INTERVAL 600 DAY) AND NOW()) as dead
create view livecates as select count(birth.id) from birth left join disposal on disposal.id = birth.id where birth.id not in (select disposal.id from disposal) as live
select livecats.id, (dead/live * 100) from livecats left join cats on livecats.id = cats.id group by livecats.id
Related
I need to compute employees' monthly salaries based on meetings attended, deductions and bonuses given;
Employees have different pay per meeting based on their job position.
The solution is:
salary = (Pay_per_minute * meetings_attended) + bonuses - deductions ;
I have four tables:
Jobs: Id, title, pay_per_meeting
Employees: Id, Name, job_id
Bonuses: Id, amount, employee_id, date
Deductions: Id, amount, employee_id, date
Meetings: Id, employee_id, date
SELECT
COUNT(meetings.employee_id) as meetings_attended,
COUNT(deductions.amount) as debt,
COUNT(bonuses.amount) bonus,
(SELECT jobs.pay_per_attendance from jobs where jobs.id = (select job_id from employees where id=meetings.employee_id)) as pay,
((meetings_attended * pay) + bonus - debt) as salary
FROM meetings
JOIN deductions ON deductions.employee_id = meetings.employee_id
JOIN bonuses ON bonuses.employee_id = meetings.employee_id
WHERE meetings.employee_id = 1
GROUP BY MONTH(meetings.date), MONTH(deductions.date), MONTH(bonuses.date)
The above query returns many incorrect values whenever i remove the salary line but gives error of unknown column pay, meetings_attended, debt and bonus, am sure something is wrong with the grouping but i can't just see it.
You can't refer to column aliases in the same select list as they're defined, you need to refer to the underlying column. And a subquery can't access an aggregate calculated in the main query. You need to repeat the aggregate expression, or move everything into a subquery and do the calculation with it in an outer query.
Also, all your COUNT() expressions are going to return the same thing, since they're just counting rows (I assume none of the values can be NULL). You probably want COUNT(DISTINCT <column>) to get different counts, and you need to use a column that's unique, so they should be the primary key column, e.g. COUNT(DISTINCT deductions.id).
Another problem is that when you try to sum and count values when you have multiple joins, you end up with a result that's too high, because rows get duplicated in the cross product of all the tables. See Join tables with SUM issue in MYSQL. The solution is to calculate the sums from each table in subqueries.
SELECT m.month, m.meetings_attended, d.debt, b.bonus,
m.meetings_attended * j.pay_per_meeting + b.amount - d.amount AS salary
FROM (
SELECT MONTH(date) AS month, COUNT(*) AS meetings_attended
FROM meetings
WHERE employee_id = 1
GROUP BY month) AS m
JOIN (
SELECT MONTH(date) AS month, COUNT(*) AS bonus, SUM(amount) AS amount
FROM bonuses
WHERE employee_id = 1
GROUP BY month) AS b ON m.month = b.month
JOIN (
SELECT MONTH(date) AS month, COUNT(*) AS debt, SUM(amount) AS amount
FROM deductions
WHERE employee_id = 1
GROUP BY month) AS d ON m.month = d.month
CROSS JOIN employees AS e
JOIN jobs AS j ON j.id = e.job_id
WHERE e.employee_id = 1
I have two tables:
table 1.a
id--entry_date-amount
============================
2---2016-04-14--$400
3---2016-04-14--$400
4----2017-07-14--$200
5---2017-07-14--$500
6---2017-05-14--$600
7----2017-06-18--$100
table 2.b
id--entry_date
===========================
2---2016-04-14--$230
3---2016-04-14--$230
4----2017-07-14--$567
5---2017-07-14--$600
6---2017-05-14--$560
7----2017-06-18--$90
8---2016-04-14--$100
from the two tables how can i get count with montwise
my desired result:
month_name--total(count form table a)--total(count form table b)--amount(table a)--amount(table b)
========================================================
April,16-----------2-------------------3---$800-$500
May,17-----------1-------------------1 --$600--$700
June,17-----------2-------------------2--$100--$800
July,17-----------2-------------------2---$700-$400
this is the demo data.
I want to show data from two tables in a single query month wise.
How can i do this?
I tried:
SELECT MONTHNAME(r.entry_date),r.a_total FROM(
SELECT
IFNULL((SELECT COUNT(tr.id) AS amount FROM a AS tr WHERE MONTH(tr.entry_date)=MONTH(t.entry_date)),0) AS a_total
,t.entry_date
FROM(SELECT tr.id,tr.entry_date
FROM a AS tr
WHERE DATE(tr.entry_date) BETWEEN '2017-07-01' AND '2018-06-30') t
GROUP BY MONTH(t.entry_date)) r
But takes 58 seconds for simple query. How can i make this in a simple query?
You can get the counts and sum from each table individually, then use UNION to combine the two result sets into one result set. Something like this :
SELECT Month_name,
SUM(aCount) AS aCount,
SUM(bCount) AS bCount,
SUM(aAmount) AS aAmount,
SUM(bAmount) AS bAmount
FROM
(
SELECT
MONTHNAME(a.entry_date) AS Month_name,
COUNT(a.id) AS aCount,
0 AS bCount,
SUM(a.amount) AS aAmount,
0 AS bAmount
FROM a
GROUP BY MONTHNAME(a.entry_date)
UNION ALL
SELECT
MONTHNAME(b.entry_date) AS Month_name,
0 AS aCount,
COUNT(b.id) AS bCount,
0 AS aAmount,
SUM(b.amount) AS bAmount
FROM b
GROUP BY MONTHNAME(b.entry_date)
) AS t
GROUP BY Month_Name;
live demo
user9131497 has a good design for the big picture. However, I would suggest stuff like this for handling the dates:
SELECT DATE_FORMAT(entry_date, "%M,%y") AS 'Month',
COUNT(*) AS 'aCount'
FROM a
GROUP BY LEFT(entry_date, 7) -- eg, "2017-03"
Try that to see what I mean.
Note that this will work beyond a year. Or did you need January values from all years to be combined?? -- That's what your solution and user9131497's will do. Mine keeps them separate.
I have a table of hours which looks like :
I want to sum the hours_spent results for this week only and group the results by the created_by person. I have this query which returns the correct data for showing only results in this week :
SELECT staff_id, first_name, last_name, date_entered, `hours_spent` as total_hours FROM hours LEFT JOIN staff ON hours.created_by = staff.staff_id where yearweek(`date_entered`) = yearweek(curdate());
But when I add the SUM(hours_spent) as total_hours and group by staff_id like the example below I get 0 results.
SELECT staff_id, date_entered, first_name, last_name, SUM(`hours_spent`) as total_hours FROM hours LEFT JOIN staff ON hours.created_by = staff.staff_id group by staff_id having yearweek(`date_entered`) = yearweek(curdate());
I'm assuming it's not working because the Having part of my statement doesn't return individual rows of dates so it breaks.
I feel like I am doing this the hard way. Should I be trying to run a second summing query on the results of the first query rather than combine it all into one (I was hoping for cleanliness). Or should I be using a subquery to filter out the dates that aren't this week then group the totals if so how could I accomplish this?
I got what I was expecting with :
SELECT staff.first_name,staff.last_name, sum(hours_spent)
FROM hours
LEFT JOIN staff ON hours.created_by = staff.staff_id
WHERE yearweek(date_entered,1) = (yearweek(curdate(),1)-1)
GROUP BY created_by
In attempting to calculate the longest goalscoring streak for a single player, I've hit a stumbling block with the >= PHP operator not performing as intended.
The data is presented in a table as follows:
date gls
------------------------
1980-08-16 2
1980-08-19 1
1980-08-23 1
1980-08-26 0
1980-08-30 1
1980-09-06 2
1980-09-13 0
... and so on
The PHP query I am using is as follows:
SELECT gls, MIN(date) as StartDate, MAX(date) as EndDate, COUNT(*) as Games
FROM (SELECT gls, date,
(SELECT COUNT(*)
FROM goalsengine G
WHERE G.gls <> GE.gls
AND G.date <= GE.date) as RunGroup
FROM goalsengine GE) A
WHERE gls>='1'
GROUP BY gls, RunGroup
ORDER BY Games
I formed the query this way in the belief that >= would tally up streaks where this player had scored one or more goals in a game. From the table above, the first three entries would represent a scoring run of three games, for example.
Instead, the query is returning streaks but only where a certain number of goals are scored i.e. despite scoring in the first three games, the first entry (where two goals were scored, not one) is ignored when the streak is returned.
To return the results, I am using the following:
while($row=mysql_fetch_assoc($result))
{
{$startrundate = date("d F Y",strtotime($row['StartDate']));}
{$endrundate = date("d F Y",strtotime($row['EndDate']));}
echo "<tr>";
echo "<td>".$row['Games']."</td>";
echo "<td class='tableprofile' style='text-align:right;'>".$startrundate." - ".$endrundate."</td>";
echo "</tr>";
$rowCount += 1;
}
By comparison, WHERE gls='0' is giving me the desired non-goalscoring streaks. I feel I have perhaps overlooked something straightforward but cannot see what.
I've managed to work out a solution to this particular issue and it works as far as I can tell, having counted some of the raw data out manually.
SELECT gls, MIN(date) as StartDate, MAX(date) as EndDate, COUNT(*) as Games
FROM (SELECT gls, date,
(SELECT COUNT(*)
FROM goalsengine G
WHERE IF(G.gls IN ('1','2','3','4','5'),1,0) <> IF(GE.gls IN ('1','2','3','4','5'),1,0)
AND G.date <= GE.date) as RunGroup
FROM goalsengine GE) A
WHERE gls IN ('1','2','3','4','5') GROUP BY IF(bg IN ('1','2','3','4','5'),1,0), RunGroup ORDER BY Games DESC LIMIT 3");
I admit it's not exactly pretty, but it's doing the job for now. I have gone to 5 in the calculation as that's the maximum number of goals scored in a single match with regards to this data set.
I want to count payment within selected date, but i can't figure it out how to do it.
Here is the example data from the my table
id starts_from payment_per_day
=======================================
1 2012-01-01 10,000.00
2 2012-01-15 10,500.00
3 2012-02-01 11,000.00
4 2012-02-15 11,500.00
5 2012-03-01 12,000.00
How do i count total payment from 2012-01-21 to 2012-02-20 ?
The total payment should be 338,500
from 2012-01-21 to 2012-01-31 = 11 days * 10,500
from 2012-02-01 to 2012-02-14 = 14 days * 11,000
from 2012-02-15 to 2012-02-20 = 6 days * 11,500
But if i do :
SELECT SUM(payment_per_day) as total FROM table
WHERE starts_from BETWEEN '2012-01-21' AND '2012-02-20'
the result is only 22,500
Any ideas ?
SELECT SUM(payment_per_day) as total FROM table
WHERE starts_from BETWEEN '2012-01-21' AND '2012-02-20';
I would first expand the range into the list of dates, then use the following query:
SELECT SUM(p1.payment_per_day)
FROM dates d
INNER JOIN payments p1 ON p1.starts_from <= d.date
LEFT JOIN payments p2 ON p2.starts_from <= d.date
AND p2.starts_from > p1.starts_from
WHERE p2.id IS NULL
You could obtain the list from the range with the help of a numbers table, like this:
SELECT DATE_ADD(#date_from, INTERVAL num DAY)
FROM numbers
WHERE num BETWEEN 0 AND DATEDIFF(#date_to, #date_from)
A numbers table is a thing worth having as it can be useful in many situations, so consider providing yourself with one. Here's a very simple script to create and initialise a numbers table:
CREATE TABLE numbers AS SELECT 0 AS num;
SET #ofs = (SELECT COUNT(*) FROM numbers); INSERT INTO numbers SELECT #ofs + num FROM numbers;
SET #ofs = (SELECT COUNT(*) FROM numbers); INSERT INTO numbers SELECT #ofs + num FROM numbers;
SET #ofs = (SELECT COUNT(*) FROM numbers); INSERT INTO numbers SELECT #ofs + num FROM numbers;
… /* repeat as necessary, each line doubles the number of rows in the table */
But, of course, you can use a loop instead.
Here's my complete testing environment on SQL Fiddle (for anyone to play with).
It seems that it is almost impossible to do query like that, counting total each day payment within selected date.
So i work around by selecting data from all starts_from dates until <= 2012-02-20 and then picking last starts_from date which is less than 2012-01-21 (that is 2012-01-15) in order to get payment_per_day 10,500.00
Thank you for viewing my question :)