MySQL select based on MySQL JSON array values - php

Hello people of the coding world.
I'm working on a small web development project and have an idea but am unsure whether or not it is applicable in pure MySQL or whether I will need to utilise some PHP code to make it work the way I need it to work. I'm not against using PHP, but feel that there is a better solution to splitting things.
I have three database tables. I'll call them A, B, and C. Tables B and C contain items that can have an item_parent. Any item in C is a child of at least one item in B, and any item in B is a child of at least one item in A. Each item, in all three tables, will have an item_id and item_level assigned to it. The ID is just a unique identifier, and serves no other purpose. The level is used to determine visibility to the viewer, as the viewer must have a level equal to or above the required level in order to view an item.
My query is that I want to be able to get the access level required in one query. This query would need to check all parents of items in table C and B for their access levels. If an item has multiple parents, it must check both and return the lowest of the two. If you can see at least one parent, you can see the child provided its level is not too high, but if you cannot see any parent then you cannot see the child regardless of child's level.
In order to get the multi-parenting system functional I've used the JSON data type for item_parent. It allows me to set a variable number of values without much change to the code used to assign or read those same values. item_id and item_level are of types INT and SMALLINT respectively.
Some sample data:
table_a
item_id | item_level
1 | 1
2 | 4
3 | 6
table_b
item_id | item_level | item_parent
1 | 2 | [1,2]
2 | 3 | [2]
3 | 7 | [1,3]
table_c
item_id | item_level | item_parent
1 | 0 | [3]
2 | 5 | [1]
3 | 8 | [1,2]
The query I want would need to run checks on the parents and return the lowest of those, then the highest of the returned data sets. Each item_parent refers to an item_id in the table directly above it.
The way I imagine this running (on table_c.item_id=1) is as follows:
table_c.item_id=1 parents are checked. The lowest level of all parents of an item is returned. Assuming we are checking the first item, the number returned would be 7, as we are checking table_b.item_id=3 (the only defined parent of table_c.item_id=1).
table_b.item_id=3 parents are checked, and again lowest value returned. We are only checking table_b.item_id=3 as it is a parent of table_c.item_id=1 and we are following the tree up. This item has two parents, so both are checked and the lowest level between them is returned. This would return a 1.
Now that we've done the level checking, we return the highest level of all returned results including the level of table_c.item_id=1. The numbers we are working with are 0, 1, and 7. The returned level would be 7, as it is the highest level of all those returned.
In the above situation, if your viewing level was 4 then you would be unable to see table_c.item_id=1 due to the level of table_b.item_id=3. However, if your level was 7 or above, you would be able to see it.
I've a few questions on how to make this work.
Can this be done by pure MySQL queries, or will I need to break things into multiple queries that are run separately with PHP processing the item_parent JSON data to prepare the next query? If so, what would the query be?
Is my use of JSON as the item_parent data type appropriate, or is there a data type that better for storing this information?
Apologies if I have not worded this very well. In my head, the idea is solid, but when it comes to explaining it I'm not sure what words to use or if I've conveyed my thoughts properly. Please let me know if edits are needed or if things are unclear.
Thank you in advance to those to take the time to read and work on a potential solution.

Following some reading of some comments and resources I was linked to, I determined that it would be more appropriate to rethink part of my database design as there is no pure MySQL way to do what I was hoping for with the existing structure.
Since I've rethought part of the database, this question becomes moot.

Related

How to import data from excel file and identify subcategory

I am making the function of importing data from the excel file with the following structure
i want loop the datas of excel then insert to categories table and determined subcategory by value of first column. Eg: 101 is sub category of 1, 101001 is sub of 101,...
I have been thinking for a long time and looking for it but not yet. Hope the helping.
Use PHP Spreadsheet https://phpspreadsheet.readthedocs.io/en/latest/
Reading from a file: https://phpspreadsheet.readthedocs.io/en/latest/topics/reading-files/#reading-files
However you parse the cat/subcat, you would want to insert it back into the table with the database ID of the parent.
To determine the parent, start with the first row, and keep it in a parents array. When you hit the next row, check the parents array if the value exists. You will have to check char by char. Then add every new category to the parents. This structure is not really ideal, what happens when PHP becomes a parent, and so on. PHP should be 10101 at any rate to follow the structure. Ruby 10102
In all honesty, you don't need second half of the number, only the parent. Just use the row id.
1, , Programming
2,1,OOP
3,2,PHP
What you are missing here is the row id. The last part is only the "sort" and can just be removed. Imagine if the column was a fixed length field which would be "easier" to parse. 3 digit for parent, and 3 digits for the sort. Start parsing from the top ..
000001 Programming
001001 OOP
What is PHP now? You aren't pointing to 001 (OOP) cause 001 is also Programming. So adding a row id, you can now point to the id that will be entered into the DB.
1 null 1 Programming # id parent sort name
2 1 1 OOP
3 2 1 PHP
4 2 1 Ruby
5 1 2 Functional

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".

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)

Handling numerical lists in php and MySQL

I'm writing a small list system which is ordered via a numerical field in the database that is dynamic
The database holds the following:
Id | position | person
======================
1 | 3 | John
2 | 1 | Jane
3 | 4 | David
4 | 2 | Emily
Now when I select that list I sort it via the position field.
What I want to do is manage this order via a backend and whilst I have the main principle down, one thing that I am struggling with is the situation where a someone updates say Emily to 3 without changing the others in that ordered list.
So the page that updates the order just has the persons name and a text box with the current order in it.
I want to try to work out a way to handle this but can't seem to grasp any possible way to do this as all will be saved at once so there is no way to determine which item has changed, and therefore should be the correct one in case of duplicate.
Any ideas?
I'd just sort like this:
...order by position, person
That way, people with the same 'position' will still be ordered reliably (by name). Leave the "fixing" up to the user.
Ofcourse, the best way to handle this would be to not bother the user at all with a 'position' field but use a draggable sortable list of some kind.
If you want to move Emily DOWN the list her position 2 become 3.
So you need to move 3 back up to 2 (which was Emilys position)
The same goes for moving UP the list. You are basically swapping positions of the next/previous record. BUT you need to check that there is a record to swap with.
PSEUDO CODE MOVE DOWN:
get Emily
update record below Emily (Emily's position+1)
IF updated okay - update Emily position
One logic behind reordering a list manually would be to reorder the entire relevant list items whenever one list position is changed. Changing 10 to 2 would require everything from 2 to 9 to be pushed +1 position forward, so the logic would be
for i in new pos+1..old pos
pos[i]++
here is an exemple that i use
first i change the position of the row, lets use calendar_event_id = 7 as exemple , and then i call reposition, that runs:
SET #position = 0;
UPDATE calendar_events SET position = #position := #position + 1
WHERE position >= 0
ORDER BY position, IF(calendar_event_id = 7, 0, 1), name
and if you deleted a row, just skip the IF(calendar_event_id = 7, 0, 1), part

How to get records in tree view from mysql / php

I have to create a tree view from the records of my table below
id user_id friend_id property_id
1 123 321 1
2 123 456 1
3 456 909 1
4 909 222 1
I have the user_id i.e 123 and property_id i.e 1 I need to know how can I make a tree with friends with whom I share this property, and afterwards with users with whom my friends share this ID.
Ok since there are several steps I'll start out on a high level. If you need help with any of those, ask again!
First of all, you'll need the "root" nodes, ie those users who don't appear as children in the friend column.
Then, for each of these users, start polling all their children. For this, define a function that gets all the children of a user and which calls itself recursively for the children of the child it finds.
This is pretty abstract, because the question is what you want to do with this structure. This depends on the last part, your presentation layer. That's what I know least about; there may be a framework which helps you visualize trees in PHP, but I don't know. There will typically be some sort of object structure with layout properties and child objects; instantiate those properties in your recursive function from the last step.
As a side node, it isn't clear if the data structure you obtain is actually a tree. If you are A, have friends B and C, and C is also a friend of B, B will show up as your friend (on level 2 of the tree) and as C's friend (on level 3). You'll have to check what's your desired behaviour in that spot and might have to, e.g., ignore C the second time you encounter it.

Categories