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.
Related
I have two tables, one with forecast production weights and one with actual production weight.
A customer can and will have multiple types and multiple seasons, and will also invoice those types over the year
Table Estimates
Customer Type Weight Season
John A 10 2018
John A 20 2018
John B 10 2018
Bill A 10 2018
Bill C 10 2017
Robert B 30 2017
Robert C 10 2018
Table Actual
Customer Type Weight InvoiceDate
John A 5 2018-10-30
John A 5 2018-10-30
John A 5 2018-10-30
John C 10 2018-10-30
Bill A 5 2018-11-1
Bill C 10 2017-11-30
Bill C 10 2017-11-30
Bill C 10 2017-11-30
Robert B 30 2017-11-10
Robert C 10 2019-2-20
Desired Query Would be as follows
select customer,
type,
sum(weight),
sum(weight)
from
estimates,
actual
where
season = 2018 and
InvoiceDate between 2018-7-1 and 2019-6-30 and
estimates.type = actual.type and
estimates.customer = actual.customer
group by
customer,
type
This give wildly large numbers
Desired result would be selecting for 2018
Customer Type Sum(Estimate) Sum(Actual)
John A 30 15
John B 10 0
John C 0 10
Bill A 10 5
Robert C 10 10
I have tried several join and union queries attempting to solve this issue
I cant quite get my head around which join to use to get the desired result
You can try below way -
select A.customer,A.type, estimated,actual
from
(
select customer,
type,sum(wieght) as estimated
from estimate where season=2018 group by customer,type
)A inner join
(
select customer,
type,sum(wieght) as actual
from actual where InvoiceDate between '2018-7-1' and '2019-6-30' group by customer,type
)B on A.customer=B.customer and A.type=B.type
I have a DB which is an Attendance List for a Training Program. In this list - First Subscriptions gets Priority - and LOCAL USERS have priority too.
DB:
ID NAME SUBSCRIPTION DATE COUNTRY
1 JOHN 2018-04-05 12:00:00 USA
2 MARY 2018-04-05 12:30:00 CANADA
3 CARL 2018-04-05 13:00:00 USA
I need a way to order the table like this:
ID NAME SUBSCRIPTION DATE COUNTRY
1 JOHN 2018-04-05 12:00:00 USA
3 CARL 2018-04-05 13:00:00 USA
2 MARY 2018-04-05 12:30:00 CANADA
CARL is from USA then I need to give priority to him, even Mary makes his subscription early.
any idea?
** IMPORTANT: Country priority changes according to the location of the training. (here the location is "USA", but can be any country)
I tried this:
SELECT * FROM SUBSCRIPTION_TABLE ORDER BY COUNTRY = 'LOCAL_COUNTRY_VAR', SUBSCRIPTION_DATE
but it did not work.
You appear to want to order first by being in the USA and then by the date:
In MySQL, you can do:
order by (country = 'USA') desc, date
I would recommend creating a separate table with the location and a priority code (integer). Inner join the two and then order by the priority code ascending. USA would have priority 1, CANADA would be 2.
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).
I'm struggling with a MySQL statement and was hoping for some guidance as I am close, but not quite there. I have a database that contains a table of property addresses and of property rental listings. The property addresses are related to a table or regions, which is related to a table of districts, which is then related to a table of suburbs.
I am trying to create a result which gives me the average rent in each suburb per month and by the number of bedrooms.
For example:
District Suburb Month YEAR YMD Bedrooms DataAverage
Nelson The Brook 01 2012 2012-01-01 00:00 1 190
Nelson The Brook 01 2012 2012-01-01 00:00 2 274
Nelson The Brook 01 2012 2012-01-01 00:00 3 341
Which I can then convert into a table as follows:
Average Rent
Beds by Suburb Jan-12 Feb-12 Mar-12 Apr-12 May-12 Jun-12 Jul-12
The Brook
1 $150 $245 $160 $285 $135 $370 $350
2 $330 $340 $380 $310 $335 $345 $355
3 $350 $380 $310 $395 $380 $350 $350
Inner City
1 $160 $245 $260 $285 $295 $300 $350
2 $360 $440 $480 $410 $535 $545 $555
3 $370 $480 $510 $595 $480 $450 $550
My Current SQL query is this:
SELECT d.name as District, s.name AS Suburb,
FROM_UNIXTIME(l.StartDate,'%m') AS Month,
FROM_UNIXTIME(l.StartDate,'%Y') AS YEAR,
FROM_UNIXTIME(l.StartDate, '%Y-%m-01 00:00') AS YMD,
p.Bedrooms,
REPLACE(FORMAT(AVG(l.RentPerWeek),0),',','') AS DataAverage
FROM properties p
LEFT JOIN listings l on l.property_id=p.id
LEFT JOIN regions r on p.region_id=r.id
LEFT JOIN districts d on d.region_id=r.id
LEFT JOIN suburbs s on s.district_id=d.id
WHERE FROM_UNIXTIME(l.StartDate) BETWEEN DATE(NOW()) - INTERVAL (DAY(NOW()) - 1) DAY - INTERVAL 11 MONTH AND NOW()
GROUP BY District, Suburb, Year, Month, Bedrooms
ORDER BY District, Suburb ASC, YMD ASC, Bedrooms ASC
Unfortunately what I am getting is the same result for each and every suburb. I think I may need to create a subquery SQL statement to get this to work properly, but I'm not entirely sure.
So I am getting something like this:
District Suburb Month YEAR YMD Bedrooms DataAverage
Nelson The Brook 01 2012 2012-01-01 00:00 1 190
Nelson The Brook 01 2012 2012-01-01 00:00 2 330
Nelson The Brook 01 2012 2012-01-01 00:00 3 350
Nelson The Brook 02 2012 2012-02-01 00:00 1 245
Nelson The Brook 02 2012 2012-02-01 00:00 2 340
Nelson The Brook 02 2012 2012-02-01 00:00 3 380
...
Nelson Inner City 01 2012 2012-01-01 00:00 1 190
Nelson Inner City 01 2012 2012-01-01 00:00 2 330
Nelson Inner City 01 2012 2012-01-01 00:00 3 350
Nelson Inner City 02 2012 2012-02-01 00:00 1 245
Nelson Inner City 02 2012 2012-02-01 00:00 2 340
Nelson Inner City 02 2012 2012-02-01 00:00 3 380
.etc.
Average Rent
Beds by Suburb Jan-12 Feb-12 Mar-12 Apr-12 May-12 Jun-12 Jul-12
The Brook
1 $150 $245 $160 $285 $135 $370 $350
2 $330 $340 $380 $310 $335 $345 $355
3 $350 $380 $310 $395 $380 $350 $350
Inner City
1 $150 $245 $160 $285 $135 $370 $350
2 $330 $340 $380 $310 $335 $345 $355
3 $350 $380 $310 $395 $380 $350 $350
Any pointers or assistance would be greatly appreciated.
Assuming that id is the primary key of each table, then according to your query text, a property is associated with a region, by virtue of the region_id column on the properties table:
FROM properties p
LEFT
JOIN regions r
ON p.region_id=r.id
A district is associated with a region (presumably, a district is a subdivision of a region.)
LEFT
JOIN districts d
ON d.region_id=r.id
and a suburb is associated with a district (presumably, a suburb is a subdivision of a district.)
LEFT
JOIN suburbs s
ON s.district_id=d.id
The net result is that every property within a region is getting associated with EVERY district within that region, and associated with EVERY suburb within each district.
So, you are getting the rent values averaged for all properties within a region.
To get rent values per suburb, you really need the relationship between a property and its suburb.
What you really need is a suburb_id column on the properties table as a foreign key to the suburbs table.
LEFT
JOIN suburbs s
ON s.district_id=d.id
AND s.id = p.suburb_id
I have a table of goalie data, snipet below
year gameid player sv% gamenum
2009 200165 John Smith 0.923 0165
2009 209754 John Smith 1.000 9754
2009 206938 John Smith 1.000 6938
2009 206155 John Smith 0.833 6155
2009 203021 John Smith 0.667 3021
2009 206472 John Smith 0.909 6472
2009 209524 John Smith 0.833 9524
2009 209351 John Smith 0.800 9351
2009 203056 John Smith 1.000 3056
2009 206761 John Smith 0.935 6761
2009 200466 John Smith 0.954 0466
2009 204171 John Smith 0.932 4171
2009 207876 John Smith 0.958 7876
2009 201581 John Smith 0.941 1581
2009 205286 John Smith 0.930 5286
2009 208991 John Smith 0.961 8991
2009 202696 John Smith 0.916 2696
2009 206401 John Smith 0.935 6401
2009 200106 John Smith 0.921 0106
2009 201381 John Smith 0.918 1381
I want to get the 10 game moving averages for each goalie, but I don't have dates or game numbers such as his first, second, third game, etc. The game ids are also assigned in the order they are played at the league level, so game 200106 could be his first game of season, and 200165 could be his 2nd, and so on.
My question is: How can I get the max(10 game moving average) and min(10 game moving average) grouped by each goalie for each year?
Also, is there a way to rank the game ids by goalie, year using MySql?
A 10 game moving average means that if you had less than 10 games, there is no meaningful average (not enough games). If you had 12 games, the average is taken between
1-10 (avg)
2-11 (avg)
3-12 (avg)
max / min across the 3 averages
The most efficient way to do this in MySQL would be to
select .. (involving 13 #variables to rownumber and rotate the last
10 values into the variables, keeping track of
#player, #year, #rownumber)
order by player, year, gameid
This will pass through the data only once, building the averages. An outer query will simply take min/max from this derived table. I'm not up for fleshing this out at the moment though.
This is one idea (fair warning:not tested)
SELECT max(mavg) FROM
(SELECT (SELECT avg(avgfield),min(gamenum) as gn FROM YourTable g WHERE g.gamenum>t.gamenum LIMIT 10),t.gamenum
FROM
YourTable t
) d
or
SELECT max(mavg) FROM
(SELECT t.gamenum FROM
YourTable t INNER JOIN
(SELECT avg(avgfield),min(gamenum) as gn FROM YourTable g WHERE g.gamenum>t.gamenum LIMIT 10) q ON q.gn = t.gamenum
) d