Mysql search query for online shop - php

I think than search is one of most trivial problems in mysql, but i have an interesting request for online shop. By the way, I use Laravel v8 Eloquent for quering, if it helps with solution.
Lets assume that we have db table goods
id | name
1 | Fried chicken leg
2 | Chicken freezed
3 | Vegetable soup with chicks
4 | Enchickened grains
and when user type chicken I want to show first a lines that starts with search query (id 2 in example table), and it would be perfect if after those entries were those that have a search query as entire word (id 1) that starts with it, followed by any other line that contains search query. I ask about it primarily because of need of pagination since shop has a thousands of entries, so I do not want to make and merge results for few subsequent requests
I tried to make two requests and merge them, making a pagination out of these results, but I have quite complicated and rather expensive resulting request that touches a few relations for goods like promo, categories, blocks and few more, so it will be a twice or more as expensive and this is not something I want to see if there is a way to optimize a request.
EDIT Example:
If I enter chicken I want to see Chicken freezed first, then (ideally but not required) Fried chicken leg and after that anything that have chicken in it. if prioritize in regex: $chicken.* -> .*\bchicken.* -> %chicken% (last one for mysql)

Related

Best MySQL Database Structure for a Yellow Pages Site

Im building a yellow pages site. I tried multiple database structures. Im not sure which one is best. Here are few I considered,
Saving all business data - name, phone, email etc in one table, list of tags in another, and mapping data id and tag id for tag-data relationship in a third table. I found this cumbersome since I'll be doing most things directly in the database (at least initially, before launch) and hence distributing everything can be problematic in my case. This one is a clean solution I must admit though.
Saving biz entries in one table with a separate column for tags (that'll contain comma separated(or JSON) tags for every entry). Then retrieving results using like query or full-text search for a tag. This one will be slower and will get more slow as db size increases. Also its not easy to maintain - suppose if I have to rename a tag.
(My Preferred Choice) Distributing biz data in different tables based on type - all banks in one, hotels, restaurants etc in separate tables. A separate table for all tags containing a rule for searching data from the table. Here is a detailed explanation.
Biz Tables:
college_tbl, bank_tbl, hotel_tbl, restaurant_tbl...so on
Tags Table
ID | Biz Table | Tag Name | Tag Key | Match Rule (col:like_query_part)
1 | bank_tbl | Citi Bank Branches | ['citi','bank'] | 'name:%$1%$2%'
2 | restaurant_tbl | Pizza Hut Restaurants | ['pizza','hut'] | 'name:%$1%$2%'
3 | hotel_tbl | The Leela Hotels | ['the leela'] | 'name:%$1%'
I'll then use 'Match rule' in like query to fetch results from 'Biz Table' for 'Tag Name'.
Im going forward with the third approach. I feel its simple, reduces the need of third data-tag relationship table, renaming is easy and performance won't get down if table has limited entries - say 1 million max per table.
Im scratching my head for the last 15 days to find the best structure and feel this one is pretty good in my case.
Please suggest a better approach or if this approach could have some issues later on.
Use Number 1. Period, full stop.
The mistake is "doing things directly in the database" rather than developing the API first.
Number 2 has one advantage -- FULLTEXT search. That can be tacked onto #1 after you have have a working API and some data to play with.
Number 3 (multiple similar tables) is a fisaco. Numerous Q&A ask about such; the reply is always "NO".

How to create menu and submenu using two tables?

Please help me how to create vertical menu or sub menu using these tables in PHP.
The two tables are cat(id,cat_name,main_cat_id) and main_cat(id,main_cat_name).
main_category table
id main_category_name
1 Hotels
2 Compressors
3 Apparel & Clothing
4 Automobile
5 Car Rentals
6 Mobiles & Accessories
7 Computers & Peripherals
8 Doctors
9 Education
category table
id category_name main_category_id
1 Pizza Center 1
2 2 Star Hotel 1
3 Hotel & Restaurant 1
4 5 Star Hotel 1
5 Air Compressor 2
6 Flare Nuts 2
7 Auto Accessories-Car Stereos 4
8 Automotive Parts, Components & Spares 4
9 Motorcycles, Scooters & Two Wheeler Parts 4
My policy of encouraging a prior attempt applies here. You've laid out the database, which is great, but you need to open a text editor and start on the PHP. You can do it!
Readers here could give you a working answer, but that suffers a number of drawbacks:
Firstly, they might misunderstand what you need, and so spend a long time on something that does not help you.
Secondly, there are several million people out there that would like people to work for them for free, and we'd be here until Doomsday if we did that.
Finally, if you get a working answer with no personal research, you might not learn anything.
Here's a suggested plan of action:
Install WAMP/MAMP/LAMP on your computer
Set up your database structure and test data in a MySQL instance on your development machine
Write some PHP code to connect to the database and run a test query on it, dumping the data in a web page
Once that works, modify the query to read the categories, using an ORDER clause to get them in the right order
Now you have enough information to create a menu. Look up the format of a <select> tag using <option> tags, each of which contains the name from your database. You'll need a value attribute for each one - this is usually the id from each row of the database
Wrap the above in a <form>
From here, you can expand your menu to contain a second level. The simplest way of doing that is to research the <optgroup> tag - much under-used, in my opinion. This allows you to set up a two-level menu that is intuitive for users and simple to read values from in code.
Give that a go?

Designing Flexible SQL Schema [for Quests]

What would be an efficient way to store "Quests" in an SQL database? Let's say the context is RPG. (Here was a previous question: How to store Goals (think RPG Quest) in SQL)
To summarize a Quest may be a combination of the following:
Discover [Location]
Kill n [MOB Type]
Acquire n of [Object]
Achieve a [Skill] in [Skillset]
All the other things you get in RPGs
The answer listed out in the link was:
For the Quest table:
| ID | Title | FirstStep (Foreign key to GuestStep table) | etc.
The QuestStep table
| ID | Title | Goal (Foreign key to Goal table) | NextStep (ID of next QuestStep)
I actually think it's pretty neat, but I have two things I would like to add:
Let's say I want to create it so that a quest can only be active only on certain days (e.g. M W F only) and/or active only at a certain time span (e.g. Halloween). What would be the ideal way of doing this?
Another thing: Let say I want to have a quest with two steps and a quest with 8 steps. We can create a table that is 8 columns wide but we would have lots of empty space. And what if the stars align and I needed an 9 step-wide quest?
The QuestStep table actually has a NextStep, sort of like a linked list, but what about Quests that you can do out of order?
P.S: As you can see it is potentially read-heavy, and the schema is potentially... non-schematic. Is NosSQL a vying option? (Redis seems memory only, so I'll more likely go with MongoDB)

Filter tags by tags and count

My mysql structure is as follows:
+----+-------------------------+-------------+-----------+--------------+
| id | title/text/moretext/img | language_id | course_id | country_code |
+----+-------------------------+-------------+-----------+--------------+
| 1 | Plenty of information | 1 | 3 | it |
+----+-------------------------+-------------+-----------+--------------+
I'm using the laravel framework to build my site.
This is a recipe. It is an appetiser (course_id 3 translates to appetiser using php arrays since page is multilingual).
This appetiser is from it. 'it' translates to Italy, again in PHP since the country names will be multilingual.
The recipe is written in English (language_id is a one to many relationship to a languages table, language id 1 is English).
This information is given in case it changes anything, which I doubt, but it's better to play it safe.
Each article will have only one of each of these tags.
What I need is a select list echoing all available options (options relating to filters in use, so if I have no recipes from South-Africa in French, South-Africa won't show in the filter list if French is the selected language).
Google yielded nothing, and I'm running out of time and my ideas are at zero. Is there any way to implement this with ease?
I've looked into http://luis-almeida.github.com/filtrify/ and think it would be exactly what I want in functionality, but I think it would be way too heavy on a large database as I'd have to query the entire database and make a list out of that. But I might be wrong.
An implementation using something like http://harvesthq.github.com/chosen/ would also be possible for selections, but I don't know how to even implement it for this.
Any help would be truly fantastic. I'm way over my head here and am all out of programming passion. I've spent a couple of days on this already and am drawing a blank. None else to ask.
A quick and dirty way to get past this (you can always come back and enhance it later) would be
SELECT DISTINCT country_code, language_id
FROM recipes
ORDER BY country_code, language_id
with whatever joins/translations are necessary to get country names and language names, then make a single dropdown from the result...
Deutschland - Deutsch
France - Francais
South Africa - Afrikaans
South Africa - English
United States - English
So each item is both the country name and the language. If most countries have only one or two languages spoken, this shouldn't be overwhelming to the user.

File or Database for searching zip code?

I have a online shopping cart, at checkout user enters his zipcode.
There are 2 payment methods, cash-on-delivery and net-banking. The courier service ships to only certain areas(identified by zipcode). And the allowed list of zipcodes for COD and Net-Banking differ. (length of list = about 2500 for COD, and about 10,000 for latter)
Should I store these lists in database or a flat file?
For database, I will be querying using SELECT, and for file, I can read the entire(or partial) list in array, and then do Binary search on it.
Which one would be faster, considering following points -
There is only one courier service now, but in future there will be more, and with different lists of there own. So I need to search in multiple lists.
There is mostly read, write would be much less. Also the list should be customisable at later point.
I would have selected Database, but I don't know if it would make things slower, and I don't want to spend time designing database, when a file might be better.
EDIT:
Say there are 2 courier companies ABC and DEF.
For file I will have 4 files (say) ABC_COD.txt, ABC_net.txt, DEF_COD.txt, DEF_net.txt. So if a customer goes for COD, I search ABC_COD, if not in there, I search DEF_COD and so on. So ok this seems to be costly, but it is also easily extensible.
Now consider database, I will have a table Allowed_zipcodes, with five columns : zipcode(int/varchar(6)), ABC_COD(boolean), ABC_net(boolean), DEF_COD(boolean), DEF_net(boolean). If the x company offers cod for y code, the corresponding column has true, otherwise false.
While this seems good for lookup, adding a company involves a change in schema.
Please consider future changes and design as well.
Database, without any hint of a doubt. More logical, and more scalable.
For some reason I think you should look at the magenta framework, isn't it already in some of the packages?
But if you want to do it yourself: Just to give you a starting point on the database model:
carrier
id(int) | name (varchar)
zipcodes
start(int) | end(int) | carrier(fk::carrier.id)
For instance:
carrier
1 | UPS
2 | fedex
zipcodes
1000 | 1199 | 2
1000 | 1099 | 1
Querying your zipcode and available carriers:
SELECT carrier.name
FROM zipcodes
LEFT JOIN carrier ON zip codes.carrier = carrier.id
WHERE
zipcodes.end >= :code
AND
zipcodes.start <= :code

Categories