I have a question on making the effective database structure for accounting code. The result I was expecting is this
| ID | Code | Name | Parent |
| 1 | 1 | Assets | |
| 2 | 1 | Tangible Fixed Assets | 1 |
| 3 | 1 | Building | 2 |
| 4 | 2 | Intangible Fixed Assets| 1 |
| 5 | 1 | CopyRights | 3 |
I've been thinking about making 3 tables such as tbl_lvl1 for main parent, tbl_lvl2 as first child and tbl_lvl3 as second child. I found about recursive query, which is just only using 1 table, but it's kind of difficult making recursive query in MYSQL.
And the result I want to view in PHP, is something like this
| Code | Name |
| 1 | Assets |
| 11 | Tangible Fixed Assets |
| 111 | Building |
| 12 | Intangible Fixed Asset |
| 121 | CopyRights |
Which structure I should make? Using 3 table or 1 table ? Thank you
You're looking for a search tree, and I'd especially suggest a B-tree.
A search tree, generally spoken, allows you to hierarchically search for all sub-nodes in a single query through nested intervals.
There are literally dozens of implementations, so you don't need to dig deep into the details, even though I would suggest it, as it's a major data structure that you should be used to.
Related
I'm struggling to come up with an efficient solution to determine user access to a specified folder, using PHP (specifically Laravel) and MySQL. I want to create a system that has Google Drive-esque functionality...
For example, Joe Bloggs creates many folders within folders, e.g. Level 1 > Level 2 > Level 3 > Level 4 > Level 5. Within any of these folders, can be any number of additional sub files and folders.
This would be the resulting database structure -
Table name: users
| id | name |
| -- | ---------- |
| 1 | Joe Bloggs |
| 2 | John Snow |
Table name: folders
| id | parent_id | author_id | name |
| -- | --------- | --------- | --------- |
| 1 | NULL | 1 | Level 1 |
| 2 | 1 | 1 | Level 2 |
| 3 | 2 | 1 | Level 3 |
| 4 | 3 | 1 | Level 4 |
| 5 | 4 | 1 | Level 5 |
| 6 | 2 | 1 | Level 3.1 |
| 7 | 2 | 1 | Level 3.2 |
Table name: folders_users
| id | folder_id | user_id | owner | read | write |
| 1 | 1 | 1 | 1 | 1 | 1 |
| 2 | 3 | 2 | 0 | 1 | 1 |
So based on record 1 in folder_users, Joe Bloggs should have owner, read & write permissions for all folders underneath Level 1. Joe Bloggs, then gives John Snow read & write access to Level 3, which in turn should give Joe Bloggs read & write access to Level 3, Level 3.1, Level 3.2 and anything created under any of these in future.
Additionally, it should be possible for a user to star a folder. I'd imagine this can simply be achieved with a separate table and query this separately -
Table name: starred_folders
| id | folder_id | user_id |
| -- | --------- | ------- |
| 1 | 7 | 2 |
The current solution I have is for every folder in the chain a user has permission to access, a record is created in the folders_users table. I feel like this is just overcomplicating things and creating excessive numbers of records. This is especially true when it comes to sharing a folder as I have to recreate the entire tree for that one user. Or, imagine if a user revokes write access to one of the shared users, the entire tree (potentially hundreds of records) has to be updated for a single flag.
What would be the best way to generate these trees, and to quickly and efficiently determine the user's access level in any given folder? I suspect the only way to do this is recursion, but I'm concerned about its efficiency? Or, should I perhaps be using something entirely different from MySQL for this? I've had a brief look into graph databases but I can't see it being a way forward for us as we don't have the infrastructure to support it.
Thanks,
Chris.
I'm writing this as a solution not the most efficient one.
You can add a column to your folders table (let's call it access) and then put ids of people that have access to that folder and it's children. I assume when you want to show information about a folder you must get its parents information from table as well so you won't need to add new queries for that.
And if you just have a access definition you can simple add records to this column like user1,user2,... and if not you can serialize an array like this
[
"read" => [user1,user2,...],
"write" => [user2]
]
Of course you can add a column for each access but if you have so many accesses this might be a solution too.
i am trying to build something like an order management tool for a car garage.
The main function of the tool is to manage repair orders and inspection orders as well
Therefore i have created this following three tables.
In the first one you can see the cars and the state of the repair and inspection.
The second one shows the information about the single repair orders the relation between the first and this is 1:n.
The last one shows the automaticly created inspection orders for each car out of the first table. This is an 1:n relation as well.
So what i try to do is to show all the open repair and inspection orders for the cars in one table. But only the open ones.
I tried it with some where statements but i got totaly confused.
My question is, how i can realise it?
+------+--------------------------+----------+------------+
| IDWZ | wz_name | wz_stand | wz_vistand |
+------+--------------------------+----------+------------+
| 1 | Querbr?cke vorn | 0 | 0 |
| 2 | Front Lateral Support | 0 | 1 |
| 3 | Rear Support | 1 | 1 |
| 4 | MID-X-Member Upper Shell | 1 | 1 |
| 5 | Front Lateral Support | 1 | 1 |
+------+--------------------------+----------+------------+
+---------+-----------------+--------------+
| IDWZTBL | rep_wzrepstatus | rep_wzfehler |
+---------+-----------------+--------------+
| 2 | 1 | REP 1 |
| 1 | 1 | REp2 |
| 1 | 1 | REp 3 MASS |
| 1 | 0 | 444 |
| 2 | 0 | |
+---------+-----------------+--------------+
+--------+-------------+
| VIWZID | vi_repstand |
+--------+-------------+
| 1 | 0 |
+--------+-------------+
Sry for that!
So the IDWZ is the foreign KEY in the second table(IDWZTBL) and in the third (VIWZID).
I tried it with
SELECT wz_name, wz_stand, wz_vistand, rep_wzrepstatus, vi_repstand FROM tbl_wz LEFT JOIN tbl_orders ON tbl_wz.IDWZ = tbl_orders.IDWZTBL LEFT JOIN tbl_vi ON tbl_wz.IDWZ = tbl_vi.VIWZID WHERE wz_stand='0' AND rep_wzrepstatus='0' ...
Only for the first table cars to the second one repair orders, that WHERE staement (WHERE wz_stand='0' AND rep_wzrepstatus='0') works fine.
But if i try to add the third table (VI) doing the same, i could fetch the result i wanna have.
What i wanna see in the Overview table is only the last open repair order and the last open inspection order.
Okay, so lets say that we have 4 columns and 3 rows of data.
|user_id|pick_1|pick_2|pick_3|
-------------------------------
|fred |C++ |java | php |
------------------------------
|eric |java |C++ | php |
------------------------------
|sam | C++ | php | java |
------------------------------
So right now, users are entering their favorite languages. The first pick(pick_1) would be the favorite programming language and the second pick (pick_2) would be the 2nd favorite programming language and etc.
How can I organize this in a way so that I can give a point value according to what columns the programming languages are. So maybe pick_1 can give 3 points, pick_2 can give 2 points and pick_3 can give 1 point.
So when you tally up the scores, C++ will have 8 points, java will have 6 points, and php will have 4 points.
That way I can give an overall ranking of what tends to be the more favorable programming language. Like so
|rank|language|points|
----------------------
| 1 | C++ | 8 |
----------------------
| 2 | java | 6 |
----------------------
| 3 | php | 4 |
----------------------
It doesn't even need to have a point system, I just couldn't think of another way to rank the languages on a scale of liked to un-liked. So if there's another way to yield the same results than please let me know. Otherwise how would I be able to do this. Preferably in just MySql. I am currently using PHP.
Thank you for reading.
You need a simpler structure
User_ID | Pick | Points
Fred c++ 3
Fred php 2
Fred java 1
This way you can do a simple sum(points) group by pick
for a SQL only solution, I would normalize your structure, and put the picks in a different table:
users: user_id; user_name
picks: pick_id; user_id; language; points;
then you would have your data in 2 tables:
| user_id | user_name |
-----------------------
| 1 | Fred |
-----------------------
| 2 | Eric |
-----------------------
| 3 | Sam |
-----------------------
| pick_id | user_id | language | points |
---------------------------------------------
| 1 | 1 | C++ | 1 |
---------------------------------------------
| 2 | 1 | Java | 2 |
---------------------------------------------
| 3 | 1 | php | 3 |
---------------------------------------------
| 4 | 2 | Java | 1 |
---------------------------------------------
| 5 | 2 | C++ | 2 |
---------------------------------------------
| 6 | 2 | php | 3 |
---------------------------------------------
| 7 | 3 | C++ | 1 |
---------------------------------------------
| 8 | 3 | Java | 2 |
---------------------------------------------
| 9 | 3 | php | 3 |
---------------------------------------------
And then use the following query to fetch the desired result:
SELECT language, SUM(points) FROM users JOIN picks ON users.user_id=picks.user_id GROUP BY language
As seen in this fiddle
This way it's also easy to add constraints so people can not vote for a language more then once, or give the same amount of votes to 2 different languages.
I have 14 tables (one for every year) with product code, firm name and invoice numbers. Main structure of table is identical (product code, ID), but there can be some variables in names of firms.
Table2011
| ID | productcode | firm1 | firm2 | firm3 | etc |
| 1 | G-00001 | 2;5;40| 32;67 | | 150 |
| 2 | G-00005 | | 50 | | |
|etc | | | | | |
Table2010
| ID | productcode | firm1 | firm2 | firm3 |etc |
| 1 | G-00001 | 1;10 | | 55 | |
| 2 | G-00003 | | 2 | | |
| 3 | G-00005 | | 50 | 40 | |
| etc| | | | | |
Table2009
...
Column Firm1 do not usually equals to same firm as firm 1 in other table
I am using table editor to work with tables (adding columns to table, editing values…).
I would like to know if it is possible to achieve result like below. It is above my PHP skills.
Product G-00001 page
…
<UL>
<LI>Year 2011: 150etc; 67firm2; 40firm1; 32firm2; 5firm1; 2firm1</LI>
<LI>Year 2010: 55firm3; 10firm1; 1firm1</LI>
<LI>Year 2009: ...</LI>
...
</UL>
…
Lemme begin with book recommendation : SQL Antipatterns. You will need it, doesn't matter if you caused this mess or ar just assigned to fix it.
If i was in your place, first thing would do would be to fix the database structure. This is madness. You do not need a new table for each year and new column for each company. Database is not a form of Excel spreadsheet.
Invoices Years Companies
----------------- ------------- ---------------
| product_code PK | | year_id PK | | company_id PK |
| company_id FK | | number | | title |
| amount | ------------- ---------------
| year_id FK |
-----------------
Where PK - primary key and FK - foreign key.
This structure would make the gathering of information much much much MUCH easier.
If you just want to display the data and not worry about the restructuring just yet you can use a JOIN to display the information from all the tables.
Although I would agree with teresko you really need to redesign that database. It is not maintainable the way it is.
I'm trying to create a nested comment system using PHP and MySQL. But I'm stuck
My Database structure is id, body, time, reply and depth.
A regular comment's reply field will be '0'. If it's replying to another it will correspond to the id of the comment it's replying to.
depth means how deep it is from the highest parent
So if this is the contents of my table...
+------+-------------+--------+---------+---------+
| id | body | time | reply | depth |
+------+-------------+--------+---------+---------+
| 1 | Some msg1 | 1 | 0 | 0 |
| 2 | Some msg2 | 2 | 0 | 0 |
| 3 | aReply1 | 3 | 1 | 1 |
| 4 | aReply2 | 4 | 1 | 1 |
| 5 | aReply21 | 5 | 3 | 2 |
+------+-------------+--------+---------+---------+
It would appear as something like this...
- (1) Some msg1
-- (3) aReply1
--- (5) aReply21
-- (4) aReply2
- (2) Some msg2
I hope it's possible using this method, it kind of goes beyond my logic.
If you can't change table structure you can just get all rows (select * from table order by time) then generate tree using PHP.
For tree storage I recommend to use Nested Sets algorithm.