Django left join query on multiple fields - mysql

I have defined three models that are as below
class City(models.Model):
city_name = models.CharField(...)
class Restaurant(models.Model):
restaurant_name = models.CharField(...)
city = models.ManyToManyFields(City)
class MenuItemCount(models.Model):
restaurant = models.ForeignKey(Restaurant)
city = models.ForeignKey(City)
menu_count = models.IntegerField()
One note is that all restaurants and cities might not exist in MenuCount. So a left join is needed.
I am trying to write the django query to retrieve a list of restaurant name, city name and menu counts. Example result would be
restaurant1, city1, 20
restaurant1, city2, None
restaurant2, city2, 30
restaurant3, city1, None
How can I write a query for this?

If you want to get all of the data in 1 query, you can use prefetch_related. You can see the documentation here. Here is the example.
City.objects.prefetch_related('restaurant_set', 'menuitemcount_set').all()

Related

MySQL n-part Query for 1-n Relationship

(Just started learning SQL a few days ago so sorry if this is a stupid question!)
I have three tables, Users, Addresses, and AddressCategories. Each User has multiple Addresses, but no more than 1 Address per AddressCategory. I would like to make a single query that searches for Users based on different criteria for each AddressCategory.
Table structure looks like:
Users:
id
1
2
AddressCategories:
category
HomeAddress
WorkAddress
Addresses:
userId category address
1 HomeAddress 1 Washington Street
1 WorkAddress 53 Elm Avenue
2 HomeAddress 7 Bernard Street
Let's say I want to search for all users whose home address contains the word "Street" and work address contains the word "Avenue". I can use the query:
SELECT * FROM Users
INNER JOIN Addresses a1 ON Users.id=a1.userId
INNER JOIN Addresses a2 ON Users.id=a2.userId
WHERE a1.category='HomeAddress' AND a1.address LIKE '%Street%'
AND a2.category='WorkAddress' AND a2.address LIKE '%Avenue%'
If I want to query across an arbitrary number of AddressCategories, I can dynamically build a query using the same principle above:
// dictionary of query parts
var q_parts = {HomeAddress: 'Street',
WorkAddress: 'Avenue'
...}
// build the query string piece by piece
let q_str1="", q_str2="";
let i=0;
for (q in q_parts) {
i++;
q_str1 += "INNER JOIN Addresses a${i} ON Users.id=a${1}.userId ";
q_str2 += (i==1) ? "WHERE " : "AND ";
q_str2 += "a${i}.category='${q}' AND a${i}.address LIKE '%${q_parts[q]}%' ";
}
// complete query string
let q_str = "SELECT * FROM Users "+q_str1+q_str2;
The way I'm doing it now works, but it's easy to make a mistake building the query string and the final string quickly becomes enormous as the number of categories grows. Seems like there must be a better way. What is the right way to perform such queries in MySQL? (Or is there a problem with how I've organized my tables?)
You can use this one for query building.
Official site: https://knexjs.org/
Npm link: https://www.npmjs.com/package/knex
A sample SQL for don't have to join many times. It is not tested, and just an idea.
You can use When/then in Where clause for verifying case by case. And finally, filter base on the total categories of a User (group by).
SELECT *
FROM
Users Inner Join
(SELECT userId,
count(category) AS categoryCount
WHERE address LIKE '%Street%' LIKE CASE
WHEN category = 'HomeAddress' THEN '%Street%'
WHEN category = 'WorkAddress' THEN '%Avenue%'
END
GROUP BY userId) a ON Users.id = a.userId
WHERE categoryCount = ? -- inject your count of all categories here, maybe get from another query

Returning value from query based on results

I have this query I'm trying to build to display specific information for a stored table. I'm needing the query to also display the Enemy Guild Name but I'm having trouble getting the query to take the Enemy Guild ID and link it to the name.
SELECT g.wPos as wPos, g.szGuildName as szGuildName, g.dwGuildExpWeek as dwGuildExpWeek, g.dwEnemyGuildID as dwEnemyGuildID, gm.wPower as wPower, gd.szName as szName
FROM guild as g
LEFT JOIN guild_member AS gm ON gm.dwGuildID = g.dwGuildID AND gm.wPower = '1'
LEFT JOIN gamedata AS gd ON gd.dwID = gm.dwRoleID
WHERE g.wPos = '1'
The output of the query right now results in the following:
Query Results Currently
What I need it to do now is take the dwEnemyGuildID it finds and then use that ID to search for the szGuildName while also displaying the other data it finds.
Use the concept of SELF JOIN, in which we will join same table again if we have a field which is a reference to the same table. Here dwEnemyGuildID is reference to the same table.
A trivial example of the same is finding Manager for an employee from employees table.
Reference: Find the employee id, name along with their manager_id and name
SELECT
g.wPos as wPos,
g.szGuildName as szGuildName,
g.dwGuildExpWeek as dwGuildExpWeek,
g.dwEnemyGuildID as dwEnemyGuildID,
enemy_g.szGuildName as szEnemyGuildName, -- pick name from self joined table
gm.wPower as wPower,
gd.szName as szName
FROM guild as g
LEFT JOIN guild_member AS gm ON gm.dwGuildID = g.dwGuildID AND gm.wPower = '1'
LEFT JOIN guild AS enemy_g ON g.dwEnemyGuildID = enemy_g.dwGuildID -- Use self join
LEFT JOIN gamedata AS gd ON gd.dwID = gm.dwRoleID
WHERE g.wPos = '1';

SQL query to find a class that contains minimum price

I have a table which contains different flight class names along with prices. Now my query result shows all of the results, flight names with corresponding classes and corresponding prices. Here is the query:
$sql = "SELECT f.dCity, f.aCity, f.date, f.flight_code, f.route, f.timeLeaving, f.timeLanding, f.price, f.class, i.airline_name ,
(SELECT location FROM iataairportcodes where iata_code='$fromm') as dLocation,
(SELECT airport_name FROM iataairportcodes where iata_code='$fromm') as dAirport,
(SELECT location FROM iataairportcodes where iata_code='$too') as aLocation,
(SELECT airport_name FROM iataairportcodes where iata_code='$too') as aAirport
FROM flights_test AS f, iataairlinescodes AS i
WHERE f.airline_code = i.iata_code
AND f.dCity = '$fromm'
AND f.aCity = '$too'
AND f.date='$newDate'";
But I want to find and display only that class, which contains minimum price; i.e., all data of that class only which contains minimum price.
(Forget about php variables please, those are from other sources)

how to get all records with multple joins in MySQL

i have 4 tables in MYSQL and i want to show count of learner_history table's status column district wise for all 36 districts, however when i query it shows only 1 district result even i tried left join to show district names weather there is data available or not it must show null or zero in its position.Data should be like this for all districts:
database structure is like this
[enter image description here][i draw the relation of tables in this image]
please suggest what query would give results like this, thanks.
i draw the relation of tables in this image13.jpg
It was pretty awkward to work from with images, but it should get you what you are asking for. Also wasn't sure what you were wanting with 'Str.#' - the example image you gave with 22 as every result wasn't the most helpful.
select
District.District_Name as District,
sum(Learner_History.`Status` = 'catchment') as Catchment,
sum(Learner_History.`Status` = 'fresher') as Fresher,
sum(Learner_History.`Status` = 'dropout') as Dropout,
sum(Learner_History.`Status` = 'missout') as Missout,
sum(Learner_History.`Status` = 'mainstrain') as Mainstrain,
sum(Learner_History.`Status` = 'pec') as PEC
from District
left join School on School.District_ID = District.District_ID
left join Learner on Learner.School_ID = School.School_ID
left join Learner_History on Learner_History.Learner_ID = Learner.Learner_ID
group by District.District_Name;

Selecting certain results using CONCAT and INNER JOIN MYSQL

I'm trying a return a result of the full name of crew members that work on the ship USS Cochrane. I've already made sure that there are some crew members that work on the ship and my code is returning an empty set. Sorry I'm still trying to figure out how to display this code as mysql on here.
SELECT CONCAT(lastName,"",firstName) AS full_name
FROM crewmember INNER JOIN
vessel
ON crewmember.serialNumber = vessel.callsign
WHERE vessel.name = 'USS Cochrane';
Try using the following query.
The query will work only if the value of serialNumber in crewmember table matches the value from callsign in vessel table
SELECT CONCAT(lastName,' ',firstName) AS full_name
FROM crewmember cc JOIN vessel vv
WHERE cc.serialNumber = vv.callsign
AND vv.name = 'USS Cochrane';