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
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 want for given date time range to get:
Airport name,
Number of flights of that airport (number of times where that airport is arrivalAirport in Flight, while departureDate of that same Flight is in the given datetime range),
Number of sold tickets of that airport (dateOfSale has to be in the given datetime range) and
Total price of those sold tickets of that airport.
I have 3 tables (Airport, Flight and Ticket):
Airport data:
id | name
1 , Madrid Airport
2 , Amsterdam Airport
3 , Belgrade Airport
----------------------------------------------
Flight data:
id | number | departureDate | arrivalDate | departureAirport | arrivalAirport | price
1 , 101 ,2019-01-29 19:21:44,2019-01-29 22:21:44, Madrid Airport , Amsterdam Airport, 600
2 , 102 ,2019-01-29 22:21:44,2019-01-30 00:21:44, Madrid Airport , Belgrade Airport , 450
3 , 103 ,2019-01-30 20:21:44,2019-01-30 22:21:44, Belgrade Airport , Amsterdam Airport, 555
4 , 104 ,2019-02-10 20:21:44,2019-02-10 22:21:44, Belgrade Airport , Madrid Airport , 555
----------------------------------------------
Ticket data:
id | FlightId | dateOfSale
1 , 3 , 2019-01-23 00:00:00
2 , 3 , 2019-01-27 10:00:00
3 , 1 , 2019-01-27 13:00:00
Example datetime range:
Minimal: 2019-01-25 19:21:44
Maximal: 2019-02-02 00:00:00
With the given datetime range, only fourth flight will not pass condition because its departureDate is not in the given range, other three flights will pass.
So now, we have Amsterdam Airport (x2) and Belgrade Airport (x1) as an arrivalAirports.
So first two columns should be represented like this:
Name of Airport | Number of Flights |
Amsterdam Airport, 2
Belgrade Airport , 1
Third one represents number of sold tickets while dateOfSale is also in the given datetime range.
In the ticket's table 3 tickets are sold, first two are bought for flight with id=3 and third ticket is bought for flight with id=1.
Since first ticket's dateOfSale is not in the given datetime range, only 2nd and 3rd ticket will pass, and they both represent arrivalAirport called Amsterdam Airport.
So end result should be:
Name of Airport | Number of Flights | Number of sold tickets | Total price
Amsterdam Airport, 2 , 2 , 1155
Belgrade Airport , 1 , 0 , 0
I tried something like this:
select a.name, count(f.arrivalAirport) as 'number of flights',
count(t.dateOfSale) as 'number of sold tickets', sum(f.price) from airport a,
flight f, ticket t where a.name = f.arrivalAirport and f.departureDate >
'2019-01-25 19:21:44' and f.departureDate < '2019-02-02 00:00:00' and
t.flightId = f.id and t.dateOfSale > '2019-01-25 19:21:44' and t.dateOfSale
< '2019-02-02 00:00:00' group by a.name;
Doing only this, it counts number of sold tickets exactly like it should but number of flights are wrong.
I am not sure how to proceed any further. What am I missing in this query and can it be done like this or it has to include join (with which I have problems also)?
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 new to this site and I need the help for following
person table:
driver_id name address
1 sankar karaikal
2 vivek chennai
3 kumaran pondy
4 siva chennai
car table
license model year
22 bmw 2014
23 toyata 2014
24 audi 2015
25 maruti 2014
owns table
driver_id license
1 22
2 23
3 24
4 25
Question is how to find who owned cars that were involved in accident in 2014.
I need a sql query for this and thanks in advance.
select name from person p
inner join
owns o on
(p.driver_id=o.driver_id)
inner join
car c on (c.license=o.license)where year='2014';
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).