Any help is greatly appreciated.
I have a table hospital:
Nurse + Year + No.Patients
A001 |2000 | 23
A001 |2001 | 30
A001 |2002 | 35
B001 |2000 | 12
B001 |2001 | 15
B001 |2002 | 45
C001 |2000 | 50
C002 |2001 | 59
C003 |2002 | 69
etc
What I am trying to do is work out which nurse
had the greatest increase of patients for the years 2000 - 2002.
Clearly B001 did as her patients increased from 12 to 45 and increase of 33
and what I am trying to produce is the result B001 | 33.
This is what I have so far:
select a.nurse,a.nopats from hospital as a
join
( select nurse,max(nopats)-min(nopats) as growth
from hospital where year between 2000 and 2002 group by nurse ) as s1
on a.nurse = s1.nurse and a.nopats = s1.growth
where year between 2000 and 2002;
but all I get returned is an empty set.
I think I need an overall max(nopats) after the join.
Any help here would be great.
Thanks!
Try this:
SELECT nurse, (max(nopats) - min(nopats)) AS growth
FROM hospital
WHERE year BETWEEN 2000 AND 2002
GROUP BY nurse
ORDER BY growth DESC
LIMIT 1;
Result: B001 | 33 due to LIMIT 1; just leave it away if you want more results.
SELECT nurse, MAX(nopats) - MIN(nopats) AS Growth
FROM hospital
WHERE year BETWEEN 2000 AND 2002
GROUP BY nurse
ORDER BY Growth
That should do it. Let me know if thats what you needed.
Related
I have a table in MYSQL(version 5.7.33) which looks like shown below:
Date
SalesRep
Sale
2021-04-01
Jack
10
2021-04-02
Jack
8
2021-03-01
Lisa
10
2021-03-02
Lisa
14
2021-03-03
Lisa
21
2021-03-04
Lisa
7
2021-03-08
Lisa
10
2021-03-09
Lisa
20
2021-03-10
Lisa
15
I want the moving average of Sale column, but don't want that to be based on the dates since the dates have gap, instead I want it based on row numbers and grouped by SalesRep. So something like this:
Date
SalesRep
Sale
MoveAvg
2021-04-01
Jack
10
10
2021-04-02
Jack
8
9
2021-03-01
Lisa
10
10
2021-03-02
Lisa
14
12
2021-03-03
Lisa
21
15
2021-03-04
Lisa
7
13
2021-03-08
Lisa
10
12.4
2021-03-09
Lisa
20
13.6
2021-03-10
Lisa
15
13.8
So the moving average is for all the dates from start to finish for a particular sales rep and then it starts over for another sales rep and so on. Is this possible to do in MYSQL? Thank you in advance!
You could use avg as a window function with a frame clause for this:
SELECT dt, salesrep, sale,
AVG(sale) OVER (PARTITION BY salesrep ORDER BY dt
ROWS UNBOUNDED PRECEDING)
AS moveavg
Without window functions, you simply join all previous rows for each salesrep:
select a.dt, a.salesrep, a.sale, avg(b.sale) as moveavg
from mysterytablename a
join mysterytablename b on b.salesrep=a.salesrep and b.dt <= a.dt
group by a.salesrep, a.dt
I have two tables. The first table is a list of lots - table name lot. There are a total of 3 lots that are managed by three people and the fields are: lot.lotID, lot.LotName
Every day, these lots will collect eggs, but sometimes, the people collecting will forget to make the entry at the end of the day. These entries go into a table called deposit. This table has deposit.DepID, deposit.DepDate, deposit.LotID and deposit.DepAmount
I need to list every lot each day and get each deposit amount. If there is none made, instead of not displaying a record, it should show that the record is a NULL value or 0. For instance if no entry is inserted into the database for lot 2 on 2018-10-11, I should see this if I query two days' worth of data:
LotID | LotName | Date | DepAmount
1 | Sarah | 2018-10-09 | 67
2 | Dave | 2018-10-09 | 84
3 | Mike | 2018-10-09 | 78
1 | Sarah | 2018-10-10 | 100
2 | Dave | 2018-10-10 | 0
3 | Mike | 2018-10-10 | 49
Alternately, it is okay if lot 2 on 10-10 says:
2 | Dave | 2018-10-10 | {null}
Can someone give me a bit of direction here? It seems like it would be insanely simple, but I can't find much on the subject. Thanks in advance!!
PS - Here are the two tables:
lot:
LotID Name
1 Jim
2 Mary
3 Jeff
4 Steve
5 Clinton
6 George
7 Jennifer
and deposit:
DepDate DepAmount UserID LotID
2018-10-09 07:09:13 150.00 1
2018-10-09 07:21:22 345.00 2
2018-10-09 19:18:33 283.00 3
2018-10-09 19:37:51 100.00 4
2018-10-09 14:11:47 357.00 8 5
2018-10-09 14:21:43 5324.00 8 6
2018-10-09 14:27:46 564.50 8 7
2018-10-10 14:32:29 3543.75 6 2
2018-10-10 23:12:40 234.00 10 3
2018-10-10 07:09:13 52.00 1
2018-10-11 07:09:13 234.00 3
2018-10-10 07:09:13 764.00 4
2018-10-10 07:09:13 123.00 6
2018-10-10 07:09:13 764.00 7
This is a tricky problem as a straight LEFT JOIN will not work due to a person having values for dates other than the one which has no value in deposit. So we need to first CROSS JOIN lot with a list of all the dates in deposit to get a set of all people and all dates i.e.
SELECT l.LotId, l.LotName, dt.Date
FROM lot l
CROSS JOIN (SELECT DISTINCT DepDate AS Date
FROM deposit) dt
Output:
LotId LotName Date
1 Sarah 2018-10-09
2 Dave 2018-10-09
3 Mike 2018-10-09
1 Sarah 2018-10-10
2 Dave 2018-10-10
3 Mike 2018-10-10
Then we can LEFT JOIN this result with the deposit table to get our list of deposits for each day, using COALESCE to convert NULL values to 0:
SELECT l.LotId, l.LotName, dt.Date, COALESCE(d.DepAmount, 0) AS DepAmount
FROM lot l
CROSS JOIN (SELECT DISTINCT DepDate AS Date
FROM deposit) dt
LEFT JOIN deposit d ON d.LotId = l.lotId AND d.DepDate = dt.Date
ORDER BY Date, l.LotId
Output:
LotId LotName Date DepAmount
1 Sarah 2018-10-09 67
2 Dave 2018-10-09 84
3 Mike 2018-10-09 78
1 Sarah 2018-10-10 100
2 Dave 2018-10-10 0
3 Mike 2018-10-10 49
Basically I have a table with several columns but I'm only interested in 4. My table looks like this:
accountID productID profit cost date country city quantity
2 10 25 15 2017/03/13 Afghanistan Kabul 330
18 3 45 42 2017/05/14 UK London 5300
25 14 22 17 2017/05/21 UK London 300
3 11 30 26 2017/04/23 Afghanistan Herat 400
What I want to achieve is to get the total quantity of products by city, by country and the ratio of city_quantity/country_quantity:
country city city_quantity country_quantity city_percentage
Afghanistan Kabul 800 1400 0.57
Afghanistan Kandahar 400 1400 0.29
Afghanistan Herat 200 1400 0.14
UK London 6500 10000 0.65
UK Manchester 3000 10000 0.3
UK Newcastle 500 10000 0.05
So far my script looks like this:
select country, city, sum(quantity)
from table
where date > dateadd(month,-1,getdate())
group by country, city
order by country, city
The where condition is because I only want the last month of data so consider it irrelevant.
How can I achieve what I want with a simple script?
You can do this using a self-join to sum the quantity grouped by country and then use that value to come up with the percentage like so:
CREATE TABLE testTable (country VARCHAR(2), city CHAR(1), quantity DECIMAL(10,2));
INSERT INTO testTable (country, city, quantity)
VALUES
('Af', 'K', 330),
('Af', 'H', 400),
('Af', 'Q', 700),
('UK', 'L', 1000),
('UK', 'M', 500);
SELECT t.country, t.city, t.quantity AS city_quantity, q.qty AS country_quantity,
CAST(t.quantity / q.qty AS DECIMAL(10,2)) AS city_percentage
FROM testTable t
JOIN
(
SELECT z.country, SUM(z.quantity) qty
FROM testTable z
GROUP BY z.country
) q ON t.country = q.country
This will give you the desired results set:
+---------+------+--------------+-----------------+-----------------+
| country | city | city_quantity| country_quantity| city_percentage |
+---------+------+--------------+-----------------+-----------------+
| Af | K | 330 | 1430 | 0.23 |
| Af | H | 400 | 1430 | 0.28 |
| Af | Q | 700 | 1430 | 0.49 |
| UK | L | 1000 | 1500 | 0.67 |
| UK | M | 500 | 1500 | 0.33 |
+---------+------+--------------+-----------------+-----------------+
Keep in mind that you'll want to check for division by zero in any production query.
I'm having difficulties with a query that absolutely has me stumped. I have a mysql database for a restaurant chain that keeps track of menu item prices from year to year. In this particular query I'm trying to obtain only the most recent price for an item at each store.
ItemMenu
pk storeNum itemNum vendorNum size price year
1 5555 2000 3150 Large 3.99 2015
2 5555 2000 3150 Large 3.75 2014
3 3333 2000 3153 Large 3.69 2014
4 2222 2000 3150 Large 3.89 2014
5 2222 2000 3150 Large 3.69 2013
ItemList
itemNum item categoryNum
2000 Mashed Potatoes 2000
2001 Green Beans 2000
2002 Coleslaw 2000
2003 Baked Beans 2000
2004 Corn 2000
ItemCategory
categoryNum type
2000 Side
2001 Dessert
2002 Drink
2003 Sauce
ItemVendor
vendorNum vendorName
3150 Acme Foods
3152 John's Vegetables
3153 Smith's Wholesale
Stores
storeNum franchisee address phone
5555 David Smith 9999 Main st 555-1212
3333 James Bond 123 Baker 867-5309
2222 Mark Jones 450 21st Ave 888-5411
What I would like to have returned is
storeNum, franchisee, item, type, vendorName, size, price, year
But only for the most recent year.
5555, David Smith, Mashed Potatoes, Side, Acme Foods, Large, 3.99, 2015
3333, James Bond, Mashed Potatoes, Side, Smith's Wholesale, 3.69, 2014
2222, Mark Jones, Mashed Potatoes, Side, Acme Foods, Large, 3.89, 2014
I hope that made sense, I'm at a complete loss of how to join the multiple tables and only pulling data for the most recent year.
Thanks,
Kevin
I have this working but have run into another issue where I may have multiple prices for a given year due to a mid-year price increase. How can I go about adding an additional sub-query to grab the max price after I've selected the max year?
My current query
SELECT m.storeNum, m.itemNum,size,m.price,year FROM ItemMenu m,
(SELECT storeNum, itemNum, MAX(year) maxYear FROM ItemMenu
GROUP BY storeNum, itemNum) yt, (SELECT storeNum, itemNum, MAX(price)
maxPrice FROM ItemMenu) mp
WHERE m.storeNum=yt.storeNum AND m.itemNum=yt.itemNum
AND m.year=yt.maxYear AND m.itemNum=5000 AND m.storeNum=205706;
Returns valid results for max year (I've selected a specific store and item to reduce the number of results).
+----------+---------+------------+-------+------+
| storeNum | itemNum | size | price | year |
+----------+---------+------------+-------+------+
| 205706 | 5000 | Individual | 1.59 | 2014 |
| 205706 | 5000 | Large | 3.69 | 2014 |
| 205706 | 5000 | Large | 3.59 | 2014 |
| 205706 | 5000 | Individual | 1.79 | 2014 |
+----------+---------+------------+-------+------+
I need to further reduce this so I only get the values of $1.79 and 3.69.
Thanks
-Kevin
You'll need to use a subquery: 1st get a set of the most recent year for a given (item,store) pairing. Next, select the price for that (item,store,year) triplet:
SELECT m.storeNum, m.itemNum,price,year FROM ItemMenu m,
(SELECT storeNum, itemNum, MAX(year) maxYear FROM ItemMenu
GROUP BY storeNum, itemNum) yt
WHERE m.storeNum=yt.storeNum AND m.itemNum=yt.itemNum
AND m.year=yt.maxYear;
You can, of course, join the various ID->name tables onto this to get the human-readable data, but I suspect your issue was figuring out how to get the most recent prices.
It should be also noted that this could be done with a JOIN rather than including the subquery in the FROM section; that may be faster.
I am trying to find an average of past records in the database based on a specific time frame (between 9 and 3 months ago) if there is no value recorded for a recent sale. the reason for this is recent sales on our website sometimes do not immediately collect commissions so i am needing to go back to historic records to find out what a commission rate estimate might be.
Commission rate is calculated as:
total_commission / gross_sales
It is only necessary to find out what an estimate would be if a recent sale has no "total_commission" recorded
here is what i have tried so far but i think this is wrong:
SELECT
cs.*
,SUM(cs2.gross_sales)
,SUM(cs2.total_commission)
FROM
(SELECT
sale_id
, date
, customer_code
, customer_country
, gross_sales
, total_commission
FROM customer_sale cs ) cs
LEFT JOIN customer_sale cs2
ON cs2.customer_code = cs.customer_code
AND cs2.customer_country = cs.customer_country
AND cs2.date > cs.date - interval 9 month
AND cs2.date < cs.date - interval 3 month
GROUP BY cs.sale_id
so that data would be structured as follows:
sale_id date customer_code customer_country gross_sales total_commission
1 2013-12-01 cust1 united states 10000 1500
2 2013-12-01 cust2 france 20000 3000
3 2013-12-01 cust3 united states 15000 2250
4 2013-12-01 cust4 france 14000 2100
5 2013-12-01 cust5 united states 13000 1950
6 2013-12-01 cust6 france 12000 1800
7 2014-04-02 cust1 united states 10000
8 2014-04-02 cust2 france 20000
9 2014-04-02 cust3 united states 15000
10 2014-04-02 cust4 france 14000
11 2014-04-02 cust5 united states 13000
12 2014-04-02 cust6 france 12000
so I would need to output results from the query similar to this: (based on sales between 9 and 3 months ago from the same customer_code in the same customer_country)
sale_id date customer_code customer_country gross_sales total_commission gross_sales_past total_commission_past
1 2013-12-01 cust1 united states 10000 1500
2 2013-12-01 cust2 france 20000 3000
3 2013-12-01 cust3 united states 15000 2250
4 2013-12-01 cust4 france 14000 2100
5 2013-12-01 cust5 united states 13000 1950
6 2013-12-01 cust6 france 12000 1800
7 2014-04-02 cust1 united states 10000 10000 1500
8 2014-04-02 cust2 france 20000 20000 3000
9 2014-04-02 cust3 united states 15000 15000 2250
10 2014-04-02 cust4 france 14000 14000 2100
11 2014-04-02 cust5 united states 13000 13000 1950
12 2014-04-02 cust6 france 12000 12000 1800
Your query looks mostly right, but I think your outer query needs to be GROUP BY cs.sale_id (assuming that sale_id is unique in the customer_sale table, and assuming that the date column is datatype DATE, DATETIME, or TIMESTAMP).
And I think you want to include a join predicate so that you match only match "past" rows to those rows where you don't have a total commission, e.g.
AND cs.total_commission IS NULL
And I don't think you really need an inline view.
Here's what I came up with:
SELECT cs.sale_id
, cs.date
, cs.customer_code
, cs.customer_country
, cs.gross_sales
, cs.total_commission
, SUM(ps.gross_sales) AS gross_sales_past
, SUM(ps.total_commission) AS total_commission_past
FROM customer_sale cs
LEFT
JOIN customer_sale ps
ON ps.customer_code = cs.customer_code
AND ps.customer_country = cs.customer_country
AND ps.date > cs.date - INTERVAL 9 MONTH
AND ps.date < cs.date - INTERVAL 3 MONTH
AND cs.total_commission IS NULL
GROUP
BY cs.sale_id
Appropriate indexes will likely improve performance of the query. Likely, the EXPLAIN output will show "Using temporary; Using filesort", and that can be expensive for large sets.
MySQL will likely be able to make use of a covering index for the JOIN:
... ON customer_sale (customer_code,customer_country,date,gross_sales,total_commission).