Database table structure query - php

Just a quick query on the best databased structure to go with for a small application, [ the database will be SqlLite or MySql and the app written in PHP if that helps]
Basically my issue is that entries will have many options and these will be likely to be added to and removed so editing the db structure is probably not the best idea. I am just wondering what the best way to store this options to the data base. In similar situations in the past I have achieved this by storing the data serialised or in JSON format to a table row, but I am wondering if this is the best option, any advice would be great.
The application is map based where a user can add/remove markers, the markers have types [ eg shop, school, hospital etc. ] the user can also add and remove types. In addition to this the use can create map views eg a map where only the school and hospitals are visible.
It is a bit hard to describe but here is a go describing the [ simplified ] table structure
markers
+---------+-----+-----+--------+-----------+
|markerID | lat | lng | typeID | name |
+---------+-----+-----+--------+-----------+
|1 | 52 | -9 | 1 | A School |
|2 | 52 | -9 | 2 | A Shop |
|3 | 52 | -9 | 1 | B School |
|4 | 52 | -9 | 3 | A Hospital|
+---------+-----+-----+--------+-----------+
marker types
+-------+-------------+--------------+
|typeID | name | icon |
+-------+-------------+--------------+
|1 | Schools | school.png |
|2 | Shops | shop.png |
|3 | Hospitals | hospitals.png|
+-------+-------------+--------------+
map view
+------+---------------------+---+
|mapID | name | ??|
+------+---------------------+---+
|1 | Schoool & Shops | ??|
|2 | Hospitals & Schools | ??|
+------+---------------------+---+
So my question is basically, what is the best way to store the information that mapID #42 should display markers with typeID #2, #5, and #23 for example.

As i understand, the Map view could have many markers ( which is logic). so i think a join table would be the best solution. A table for example called MapMarkers that has the following structure :
MapMarkers
| id | MapID | MarkersID | ?? | ( you can add other infos for example if you want to store personnalized maps for each client you can add userID)

You should use a third table which represents a relation between two tables:
mapView ---- < mapView-markerType > ---- markerType
mapView-markerType would have the attributes: | id | mapID | typeID |
(you should get a shorter name than mapView-markerType, obviously)
EDIT
Considering the changes you made on the post, you would get:
mapView_markerType
id* | mapId | typeId
--------|----------|----------
1 | 1 | 1
2 | 1 | 2
3 | 2 | 1
4 | 2 | 3
EDIT2
So, to further explain what I meant on the comment below:
map view
+------+---------------------+----------+
|mapID | name | typeComb |
+------+---------------------+----------+
|1 | Schoool & Shops | {1,2} |
|2 | Hospitals & Schools | {1,3} |
+------+---------------------+----------+

Related

How to best structure a database while keeping track of dataset changes

I've got a small CRM and I'm trying to figure out the best way to designing the DB tables.
I've currently got a single table for users that got around 30 columns which I alter from time to time. Since I am storing two different information on that table (user + company information) I was thinking of splitting that table into 3 (user + company + connection between these 2) but I am also interested in keeping a copy of any changes that are being made in these rows.
So going from:
user_id | firstname | last_name | company_name | company_city | company_subject | rank | status
1 | John | Borrows | Boink INC | NY | Web dev | 1 | 1
2 | Mike | Smith | Smithin INC | OC | Laywer | 1 | 2
3 | Mary | Anton | Caffin | SJ | Moving | 2 | 1
to something like this
user_id | firstname | last_name | rank | status
1 | John | Borrows | 1 | 1
2 | Mike | Smith | 1 | 2
3 | Mary | Anton | 2 | 1
comp_id | company_name | company_city | company_subject
1 | Boink INC | NY | Web dev
2 | Smithin INC | OC | Laywer
3 | Caffin | SJ | Moving
con_id | user_id | comp_id
1 | 1 | 1
2 | 2 | 2
3 | 3 | 3
But I'm not sure how to track the changes when for example a user changes the company name or some other info on user's table etc.
Just follow the normalization rules for structuring your database tables. You will find anything you need for that by just searching for database normalization.
Regarding your "update-history" you could add a Timestamp to your datasets and/or a separate boolean field "outdated" to be able to filter out the latest information.
Would be the simplest solution that comes into my mind.

Get results from table as diverse as possible

I want to retrieve rows from a table based on some search criteria. The results I get have to meet those criteria and should additionally deliver a sample of the data that is as diverse as possible. A query with the same search criteria should always return the same sample though. So using RAND() in the query is no solution. The results are used to be displayed on a PHP driven website.
Example
I've got a table with accommodations, e.g. hotels, Bed&Breakfast or campgrounds. For every accommodation, there are additional informations like rating, budget, city and region. So the table basically looks like this:
| id | name | type | rating | budget | city | region |
| 1 | A Name | Hotel | 2 | 2 | New York | East |
| 2 | B Name | B&B | 3 | 2 | New York | East |
| 3 | C Name | Hotel | 4 | 3 | New York | East |
| 4 | A Name | Hotel | 3 | 4 | Chicago | Central |
| 5 | D Name | B&B | 4 | 3 | Chicago | Central |
| 6 | E Name | Hotel | 2 | 2 | Omaha | Central |
| 7 | F Name | Hotel | 5 | 4 | Omaha | Central |
| 8 | G Name | Camping | 2 | 4 | Yosemite | West |
I now need a query that gets ten accommodations from e.g. region='Central' which contains as many cities as possible, as many accommodation types as possible, cheap accommodations as well as expensive ones and so on. I don't need a mathematically perfect solution, just something consistent.
Idea 1
I could query the table multiple times, with several different where clauses and mix the results. But querying multiple times is a big drawback for a web application.
Idea 2
I could introduce an additional column random that is filled by a random value while inserting the data and then do an order by random. The drawback of this solution is that random is a bad heuristic for what I want to accomplish.

Mysql join query multiple values

I have a table called facility.
Structure looks as follows:
id | name
---------
1 | Hotel
2 | Hospital
3 | medical shop
I have an other table which is taking data from the above table and keeping multiple values in one column. View looks like below:
id | facilities
---------------
1 | Hospital~~medical shop~~Hotel
2 | Hospital~~Hotel
3 | medical shop~~Hotel
If I want to join these two tables how does the query look like?
I tried this, but it didn't work:
select overview.facilities as facility
from overview join facility on facility.id=overview.facilities;
you can do this with a bit of hackery
select o.facilities as facility
from overview o
join facility f on find_in_set(f.facilities, replace(o.facilities, '~~', ','));
I would highly recommend you change the way you are storing data. currently it is considered un normalized and that quickly becomes a monster to deal with
you should change your table structure to look something more like this
+----------+--------------+
| facility |
+----------+--------------+
| id | name |
+----------+--------------+
| 1 | Hotel |
| 2 | Hospital |
| 3 | medical shop |
+----------+--------------+
+-----------+-------------+
| overview |
+-----------+-------------+
| id | facility_id |
+-----------+-------------+
| 1 | 2 |
| 2 | 3 |
| 3 | 1 |
| 4 | 2 |
| 5 | 1 |
| 6 | 3 |
| 7 | 1 |
+-----------+-------------+
Code Explanation:
basically you are wanting to find the matching facilities in the overview. one handy function MySQL has is FIND_IN_SET() that allows you to find an item in a comma separated string aka find_in_set(25, '11,23,25,26) would return true and that matching row would be returned... you are separating your facilities with the delimiter ~~ which wont work with find_in_set... so I used REPLACE() to change the ~~ to a comma and then used that in the JOIN condition. you can go from here in multiple ways.. for instance lets say you want the facility id's for the overview.. you just add in the select GROUP_CONCAT(f.id) and you have all of the id's... note if you do that you need to add a GROUP BY at the end of your query to tell it how you want the results grouped

MySQL - How do I order based on columns from another table

I have these tables:
Table 'Data':
| Customer | Category | Brand | Market | A | B |
|==========|==========|=======|========|===|===|
| Bill | 5 | 4 |1 |2 |9 |
| Bill | 5 | 4 |1 |6 |15 |
| Bill | 5 | 4 |1 |1 |30 |
| Greg | 7 | 9 |3 |5 |1 |
| Amy | 9 | 2 |1 |1 |8 |
Table 'Customer':
| Cust | Mkt | SubMkt |
|======|=====|========|
| Bill | 1 | NY |
| Bill | 2 | Arizona|
| Bill | 3 | Cali |
| Greg | 1 | Ohio |
| Amy | 1 | Texas |
Table 'Sort':
| SubMarket | SortBy |
|===========|========|
| Cali | A |
| Ohio | B |
| Arizona | A |
| NY | A |
I need to select all from 'Data' ordered by a few different columns and then either A or B depending on what 2 other tables say.
SELECT *
FROM Data
ORDER BY Customer, Category, Brand, Market, (A or B)
Basically, Customer and Market in table Data links to Cust and Mkt in table Customer, and then SubMkt in table Customer links to SubMarket in table Sort. Then SortBy in table Sort would be the column I need to sort by in table Data. Hope that makes sense.
So, in the above example, all of the rows in Data containing both "Bill" for Customer and "1" for Market would be sorted by column A.
I started to write an array of objects in PHP and then I would sort the array based on an object property but this would actually require a huge overhaul on my existing code. I assume what I'm looking for can be done with a fairly straight forward query in MySQL but I don't know MySQL well enough to write that query. Any help would be appreciated!
Edit: I should have mentioned, these are just partial tables. The actual tables I'm working with are thousands of rows and every "SubMarket" does have a matching "SortBy".
Edit 2: Clarified that Customer and Market is needed in table Data to link to Cust and Mkt in table Customer.
this is just an answer showing how to do the joins.. Ignacio should have the accepted answer as he provided the hard part first :)
SELECT d.*
FROM data d
JOIN customers c on c.cust = d.customer AND c.mkt = d.market
JOIN sort s on s.submarket = c.submkt
ORDER BY
d.Customer,
d.Category,
d.Brand,
d.Market,
CASE s.sortby
WHEN 'A' THEN d.A
WHEN 'B' THEN d.B
ELSE 9999999
END
You need a CASE expression.
CASE `Sort`.`SortBy`
WHEN "A" THEN `Data`.`A`
WHEN "B" THEN `Data`.`B`
ELSE NULL
END CASE
The ELSE NULL part is optional, but it can help reveal data problems.

Displaying Data From Multiple MySQL Tables

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.

Categories