Joins on database engine vs on client-side [duplicate] - mysql

This question already has answers here:
MySQL query in a loop vs using a SQL join
(2 answers)
Closed 10 months ago.
I am creating an API with express.js for a food app and I can't figure out what is the best (most efficient) way to query the data and send it to the client-side. Any help is much appreciated.
I have a table called Restaurants
id
name
img_url
address
1
restaurant 1
link to img 1
address 1
2
restaurant 2
link to img 2
address 2
Another table called categories
id
name
1
Pizza
2
Pasta
And a restaurant can be in one or more categories, so I have another table for the many-to-many relationship
restaurant_id
category_id
1
1
1
2
2
1
2
2
Now on the home page of the app, I need to send a get request to the server and get in return all the restaurants and the categories so that I can display them all in one scroll view with the category name and below it all the restaurants that belong to it.
The first approach that got to my mind is to join all three tables
SELECT *
FROM Restaurants r
INNER JOIN RestaurantCategory rc ON r.id=rc.restaurant_id
INNER JOIN Categories c ON c.id=rc.category_id;
which will give me a result similar to this
id
name
img_url
address
category
1
restaurant 1
link to img 1
address 1
Pizza
1
restaurant 1
link to img 1
address 1
Pasta
2
restaurant 2
link to img 2
address 2
Pizza
2
restaurant 2
link to img 2
address 2
Pasta
And then I would somehow either on the client-side or the server-side loop on the result and make a list for each category and put in it any restaurant that is in that category.
Instead of doing the lists myself I also thought about first selecting the categories and then doing a for loop on the server-side to get the restaurants for each category, but I am not sure if in this case having multiple select statements is better than one.
I didn't like this approach because of how the table returned is having all the information about the same restaurant repeated more than once for each category. If I have 100 restaurants (with more columns than in the example above) for example and each is in maybe 3 categories, I will get 300 records, which I think will be a big amount of data being sent from the server to the client and it is all repeated.
The second approach is to Select each table alone, then do the join on the client-side myself.
I know that I should let the database engines do the joins for me because they are more powerful but I was thinking maybe if the users have a bad internet connection or something it will be worse to have the amount of data doubled or tripled?

Use a GROUP BY clause:
SELECT *
FROM Restaurants r
INNER JOIN RestaurantCategory rc ON r.id=rc.restaurant_id
INNER JOIN Categories c ON c.id=rc.category_id
GROUP BY c.id

Related

Access: finding the corresponding value of maximum value

I have a database in which I perform an audit on a set of required documents, for several locations of those documents.
So I have a table named Locations and a table named Documents, which are correlated through a 2 x 2 relationship.
Every document can have multiple versions. In my query, I want to see only the most recent version of each document, so the max(Id).
Now, every version can be 'audited' (checked) multiple times, for example 2 times each year. Each Audit/check is stored in a record, and I want to show only the most recent audit for each document, so Max(ID).
This is my Selection Query:
SELECT [~Locations].Location, [+DocuProperties].Category, [~Documents].[Document name], Max([DocuVersion].Id) AS MaxDocuID, Max([Audit].Id) AS MaxAuditID, [Audit].Conclusion
FROM ([~Documents] INNER JOIN ([~Locations] INNER JOIN ([+DocuLocation] INNER JOIN [+DocuProperties] ON [+DocuLocation].Id = [+DocuProperties].DocuLocation) ON [~Locations].Id = [+DocuLocation].Location) ON [~Locations].Id = [+DocuLocation].DocuName) INNER JOIN (DocuVersion INNER JOIN 2Audit ON [DocuVersion].Id = [Audit].DocuVersion) ON [+DocuProperties].Id = [DocuVersion].DocuLocation
GROUP BY [~Locations].Location, [+Docuproperties].Category, [~Documents].[Document name], [Audit].Conclusion
However: I do not wish to Group on Audit Conclusion, I wish to show the Audit conclusion that corresponds to the Max(Id) of that Audit.
So for every most recent Audit, I want to show the Conclusion. This conclusion I want to show for each Document, grouped byCategory and grouped byLocation.
I know I need to build a nested subquery of some form, but I just can't get any code to work.
I hope anybody can help.
The basic idea is like this:
Table 1
DocuProperties
Id Location Category
1 15 1
2 15 1
3 14 2
(every location can have multiple document properties a.k.a. objects)
Table2
DocuVersion
Id DocuProperty DocumentEndDate
1 1 01-01-2022
2 1 20-07-2023
3 2 31-07-2023 etc.
4 3 01-10-2023
(every DocuProperties can have multiple versions, I have to check If they are still valid, but also on some other criteria ).
Table 3
Audit
Id DocuVersion Conclusion
1 1 Not Valid
2 1 Not Valid
3 2 Valid
4 4 Valid
(every version can be audited multiple times. Every audit can have a different conclusion)
Which I would like to translate into the following:
LASTAudit (a.k.a. the most recent audit of the most recent version of the most recent property)
Location DocutPropertyId DocuVersionId AuditId Conclusion
15 2 2 2 Not Valid
14 3 4 4 Valid
The ID’s were easy to get right, as those were just Max(Id) functions. The problem was to get the Conclusion corresponding to that audit of that version of that object.

Fetch rows either with one matching condition or all rows if no matching rows

I have a simple table
**targeted_url_redirect targeted_countries msg_type non_targeted_url**
http://new.botweet.com india,nepal,philippines NEW http://twisend.com
http://expapers.com United States,Canada OLD http://all.twisend.com
https://tweeasy.com india,england OLD http://all.twisend.com
I receive traffics on my website followerise.com and I want to redirect users to specific urls based on their countries as defined in the above table. I am able to write query to get rows for the users who coming from the countries that are target stored in my database. But I am looking for a solution to get all the rows if the targeted_countries condition not return any rows.
I written below queries.
SELECT * FROM tweeasy_website_redirection
WHERE message_type='OLD'
AND targeted_countries LIKE '%#country%'
This query gives me desired rows if visitor coming from the countries india,england,United States,Canada
But I want all rows (2nd and 3rd) should be fetched if a user coming from the countries not specified in targeted_countries column.
Also let me know if I need to restructure this table into 2 or more tables to get desired result.
One option uses not exists:
SELECT t.*
FROM tweeasy_website_redirection t
WHERE
t.message_type = 'OLD'
AND (
t.targeted_countries LIKE '%#country%'
OR NOT EXISTS (
SELECT 1
FROM tweeasy_website_redirection t1
WHERE t1.targeted_countries LIKE '%#country%'
)
)
When it comes to the structure of your table: one design flaw is to store list of values as CSV list. You should have two separate tables: one to store the urls, and the other to store the 1-N relationship between urls and countries. Something like:
table "url"
id targeted_url_redirect msg_type non_targeted_url
1 http://new.botweet.com NEW http://twisend.com
2 http://expapers.com OLD http://all.twisend.com
3 https://tweeasy.com OLD http://all.twisend.com
table "url_countries"
url_id country
1 india
1 nepal
1 philippines
2 united states
2 canada
3 india
3 england
select * from tweeasy_website_redirection
where targeted_countries not in (SELECT targeted_countries FROM stack WHERE targeted_countries LIKE '%#country%')

exact search and similar search combining two tables with multiple keywords mysql

Say I've two tables products and brands having below data.
tbl_products
ID Name BrandID Price
1 Keyboard 1 100
2 Keyboard 2 120
3 Keyboard wireless 1 130
4 Keyboard wireless 2 150
tbl_brands
ID Name
1 Microsoft
2 Dell
3 HP
What I want is when I type 'Microsoft Keyboard' or 'Keyboard Microsoft' then it should list me product ID 1 and 3 not 2 or 4 even 2 or 4 has keyboard. I may search for more keywords but it should give me only the items matching itself.
SELECT p.*, b.Name BrandName FROM tbl_products p INNER JOIN tbl_brands b ON b.ID = p.BrandID WHERE p.Name LIKE '%Microsoft%' OR b.Name LIKE '%Microsoft%' OR p.Name LIKE '%Keyboard%' OR b.Name LIKE '%Keyboard%'
Please help me to write proper MySQL query or any schema change with query..
Appreciate the question. Though I don't have exact answer but surely can discuss one approach to solve the problem.
STEP 1 Get BRAND NAME+NAME as single string.
STEP 2 Tokenise the entered STRING. Example Microsoft Keyboard = Mincrosoft,Keyboard Following Link for spliting the entered data. How do I split a string so I can access item x?
STEP 3 DO a like query on the string obtained in step 1.

How to retrieve hierarchial parent-child data related by multiple tables?

I have a website that contains guitar lessons and exercises, broken down by category. So you could have category scales. Then a lesson scales lesson1, which could contain exercise1_1, exercise1_2. Likewise for other categories and lessons with exercises.
Lessons and exercises are considered nodes (it is a Drupal site). So there is a node table that has node ids, node type (lesson or exercise) and titles.
Other info fields for these nodes (lesson/exercise text, etc) are stored in separate tables for each field. For instance there is a drupal_field_data_description table that contains description for each lesson and exercise.
Categories are stored in a taxonomy term table.
Relations among categories are handled via a taxonomy index table that establishes child-parent relation (so you could have scales, scales->major scales, etc). For my question, I am just considering one depth of category.
Categories of lessons and exercises are stored in a table drupal_field_data_field_category, which maps lessons and exercises to the category they are a part of.
Exercise-Lesson child-parent relations are stored in a table drupal_field_data_field_lesson that maps exercises to lessons.
Here is example data:
The categories (drupal_taxonomy_term_data):
tid vid name
1 2 Scales
2 2 Arpeggios
The lessons and exercises (drupal_node):
nid type title
1 lesson Lesson1
2 lesson Lesson2
3 exercise Ex1_1
4 exercise Ex1_2
5 exercise Ex2_1
6 exercise Ex2_2
The description field for the lessons and exercises (drupal_field_data_field_description):
entity_type bundle entity_id field_description_value
node lesson 1 Lesson1Summary
node lesson 2 Lesson2Summary
node exercise 3 Ex1_1Summary
node exercise 4 Ex1_2Summary
node exercise 5 Ex2_1Summary
node exercise 6 Ex2_2Summary
The mapping of lessons and exercises to the taxonomy (drupal_taxonomy_index):
nid tid
1 1
2 1
3 1
4 1
5 1
6 1
The mapping of lessons and exercises to the category (drupal_field_data_field_category) (this one almost seems unnecessary because of the taxonomy index):
entity_type bundle entity_id field_category_tid
node lesson 1 1
node lesson 2 1
node exercise 3 1
node exercise 4 1
node lesson 5 1
node lesson 6 1
The mapping of exercises to lessons (drupal_field_data_field_lesson):
entity_type bundle entity_id field_lesson_target_id
node exercise 3 1
node exercise 4 1
node exercise 5 2
node exercise 6 2
So... with this structure, I can't figure out how to build a query that will return a result of the form
Lesson1 Lesson1Summary
Ex1_1 Ex1_1Summary
Ex1_2 Ex1_2Summary
Lesson2 Lesson2Summary
Ex2_1 Ex2_1Summary
Ex2_2 Ex2_2Summary
Note that Lesson1 and Lesson2 are in the same category.
I need to return such data, because for a category page (that has no subcategories), I need to display a table for each lesson that shows the exercises in the lesson.
I could do all this in multiple queries, but I am really trying to better understand SQL joins and grouping. Also, I am not dead set on a result set as shown above. I am open to whatever result set will let me readily display the data (which I will do via PHP) in the fashion as I described.
The SQL fiddle is here
How would you recommend building such a query to extract a lesson and its exercises grouped in a logical way (e.g. how I show above)?
Seems getting lesson and exercises in this way would amount to a self join, with a variety of inner joins on the other tables but I just can't piece it all together...
Well, after much reading, I think I figured it out:
SELECT n.title, d.field_description_value, n.nid, l.field_lesson_target_id from drupal_node n
JOIN drupal_field_data_field_description AS d ON d.entity_id = n.nid
JOIN drupal_taxonomy_index AS t ON t.nid = n.nid
LEFT JOIN drupal_field_data_field_lesson AS l ON l.entity_id = n.nid
ORDER BY COALESCE(l.field_lesson_target_id, n.nid), l.field_lesson_target_id, n.nid
I based above on this post
My sqlfiddle is here.
This is definitely new territory for me, and while above works, I wish I understood the ORDER BY and GROUP BY nuances to understand where/how to use them.

MySQL - Search for record within nested tables

I have a MySQL database with two tables. The first is a hierachy of departments, whereby each record has a parent record from within the same table, and the top level has a parent_id of 0.
The second is a table of products. Each product can live anywhere in the tree of departments.
I need to be able to let people search for a product by specifying a department to search within, but for the search to look within all the sub-departments of the specified department. Can this be done in a single query?
My "Plan B" is to store a list of parent ids with each product in a new field, and search that field using a LIKE query, but that seems nasty somehow.
Dummy data:
id|parent_id|name
1|0|Main 1
2|0|Main 2
3|0|Main 3
4|1|Sub 1-1
5|1|Sub 1-2
6|1|Sub 1-3
7|4|Sub 1-1-1
8|4|Sub 1-1-2
9|4|Sub 1-1-3
id|department|product
1|1|test product 1
2|4|test product 2
3|7|test product 3
SELECT * FROM products WHERE department = 1 ; want to receive all three products
SELECT * FROM products WHERE department = 4 ; want to receive products 2 and 3
SELECT * FROM products WHERE department = 7 ; want to receive only product 3