Database design - using JSON to store info - mysql

I have a database listing campsites
There is a main table tblSites that contains the unique data eg name, coordinates, address etc and also includes columns for each facility eg, Toilet, Water, Shower, Electric etc where these are just 1=Yes, Null= no
This would be searched by something like
SELECT id FROM tblSites WHERE Water = 1 AND Toilets = 1
There is another related table tblLocations which contains location type (ie Near the sea, Rural, Mountains, By a river etc.
This means the table has a lot of columns and doesn't allow for easy updating if I want to add a new category.
This would be included in a search like this
SELECT M.id, L.* FROM tblSites AS M
LEFT JOIN tblLocation AS L ON M.ID = L.ID WHERE M.water=1 AND L.river=1
What I am considering is adding a column eg facilities that would contain an json string of facilities as a numbered key eg [1,3,4,12] each of the numbers represents an available facility, and another column for locations in the same format eg [1,3,5]
THis does allow me to reduce the table size and add additional facilities or locations without adding extra columns but is it a good idea performance wise?
i.e. a search would now be something like
SELECT id FROM tblSites WHERE (facilities LIKE '%1,%' AND facilities LIKE '%4,%' AND locations LIKE '%1,%')
Is there a better query that could be used to see if the field contains a key number in the array string?

Your WHERE clause is not working fine while using like '%1,%'.
if your facilities is string (TEXT or varchar ...) and searching value in stringed json array [2,3,12,21,300], where facilities like '%1,%' is true and matching with '21,' and if you want find where facilities like '%300,%' it never match that mentioned array!
So, searching json array in string format is rejected.
if your MySQL version is greater than 5.7.8, it supports native json as JSON type for columns.
When you store your data in json column in MySQL (by JSON_INSERT()) you're able to search them in where by WHERE JSON_CONTAINS(facilities,1)
But the best solution is re-design your table structures and relations as #Robby commented below your question.

Related

Search in multiple column with at least 2 words in keyword

I have a table which store some datas. This is my table structure.
Course
Location
Wolden
New York
Sertigo
Seatlle
Monad
Chicago
Donner
Texas
I want to search from that table for example with this keyword Sertigo Seattle and it will return row number two as a result.
I have this query but doesn't work.
SELECT * FROM courses_data a WHERE CONCAT_WS(' ', a.Courses, a.Location) LIKE '%Sertigo Seattle%'
Maybe anyone knows how to make query to achieve my needs?
If you want to search against the course and location then use:
SELECT *
FROM courses_data
WHERE Course = 'Sertigo' AND Location = 'Seattle';
Efficient searching is usually implemented by preparing the search string before running the actual search:
You split the search string "Sertigo Seattle" into two words: "Sertigo" and "Seattle". You trim those words (remove enclosing white space characters). You might also want to normalize the words, perhaps convert them to all lower case to implement a case insentive search.
Then you run a search for the discrete words:
SELECT *
FROM courses_data
WHERE
(Course = 'Sertigo' AND Location = 'Seattle')
OR
(Course = 'Seattle' AND Location = 'Sertigo');
Of course that query is created using a prepared statement and parameter binding, using the extracted and trimmed words as dynamic parameters.
This is is much more efficient than using wildcard based search with the LIKE operator. Because the database engine can make use of the indexes you (hopefully) created for that table. You can check that by using EXPLAIN feature MySQL offers.
Also it does make sense to measure performance: run different search approaches in a loop, say 1000 times, and take the required time. You will get a clear and meaningful example. Also monitoring CPU and memory usage in such a test is of interest.

MySQL storing list of values

I have 300,000 rows in my db and I am doing a full text search like this:
select * from CT
where match (`Abstract`)
against ('tissue engineering' in natural language mode);
Right now it is checking to see if the word "tissue engineering" is found in the abstract, however, I have a list of around 50 terms I need to check for. My first response is to create a list of all the values and check it against the list. Is this possible with MySQL?
#How to write this in MySQL?
terms = ['abdomen', 'abdominal', 'acl'...'vertebral', 'waist', 'wrist']

Is there a way to separate data from one field in mySQL?

We have a drug column in our database and this contains the Drug Name (e.g. Xanax) and its size (0.5mg).
E.g. Drug Name: Xanax 0.5mg
However, there's a need for us to separate the two data without creating a new column for the size as doing so will have a huge effect on the database structure. We just need to populate a list with just the drug name without its size based from this single field / column.
Is there a way to extract just the name of the drug? Let's say by forcing the user to add a parenthesis around the drug size (e.g. Xanax (0.5mg))? Meaning just extract all the string that comes before the first "(" character?
Or is there a better way?
Try this:
mytable:
id name
1 Xanax (0.5mg)
Query:
select id, substring_index(name,'(',1) from tb_mx;
Will return:
1, Xanax
So use it accordingly.
You can store drugĀ“s data in JSON format
{"some_unique_id":{
"name": "Xanax",
"quantity": "0.5mg"
}}
And then use Functions That Search JSON Values for MySQL 5.7 to get what parameter you need.
I have some experience with DB used in Pharma industry and I can say it's not ok do doit like that.
Here is what i think u must do (normalize)
Table UM (like mg,ml,etc)
Table Packing (like quantity per pice, pice nr , FK ID_UM)
Table Drugs (name, fk id_packing)
Don't worry about space. Tables UM and Packing will have alot of reused ID, and a column int take less that than varchar.
Or can used JSON ideea, but then you will have some problemes in reporting part.

Selecting and compare one value with values in 2 columns of the DB

I have one value, that represents a zip code.
I need to see which city belongs to this zip code by comparing the given value with the values in two columns of the DB.
This is my _cities table:
city (name of the city, VARCHAR)
zipcode_start (the first zip code available, VARCHAR )
zipcode_end ( the last zip code available, VARCHAR ).
Where I leave zipcodes are numbered in sequence.
So if I have for example: city = Rome, zipcode_start = 00118 and zipcode_end = 00199 and the given zipcode is 00119, how do I get the city Rome from the DB?
00119 in this case is included in the sequence 00118 - 00199, so the DB should return Rome.
I can do this in many ways with PHP, but I am looking for an elegant way to do it directly with a SQL statement.
Is this possible?
Thanks for any help
I'd use BETWEEN, or if you don't like that, you can use >= and <=. And if you prefer joins over where clauses, you can even join on an inequality sometimes.
For example,
select city
from my_cities
where zipcode between zipcode_start and zipcode_end
You have to deal with getting the variable into that statement, but I get the impression that you can handle that part already. Is this what you are trying to do? I sort of doubt it, but that's all I get out of your question.

Left join table ON row with JSON values?

This one is tough , I have 2 tables that I need to join on specific row and issue is that first table row is json value
this is the json row from table items
[{"id":"15","value":"News Title"},{"id":"47","value":"image1.jpg"},{"id":"33","value":"$30"}]
this is the table attributes that I need to join on json ID and get the actual attribute name like Title , Image , Price
id Name
15 Title
47 Image
33 Price
so the start is
SELECT item_values FROM ujm_items
LEFT JOIN?????
WHERE category = 8 AND published = 1 ORDER BY created DESC
but left join on json , have no clue.
any help is appreciated.
... and this is why you don't store structured data in a single SQL field. It negates the whole purpose of a relational database.
Unless you've got a DB that includes a JSON parser, you've got two options:
a) unreliable string operations to find/extract a particular key/value pair
b) slurp the json into a client which CAN parse back to native, extract the key/values you want, then use some other ID field for the actual joins.
SELECT ...
LEFT JOIN ON SUBSTR(jsonfield, POSITION('"id:"', jsonfield)) etc...
Either way, it utterly torpedoes performance since you can't use indexes on these calculated/derived values.
note that this won't work as is - it's just to demonstrate how utterly ugly this gets.
Fix your tables - normalize the design and don't store JSON data that you need to extract data from. It's one thing to put in a json string that you'll only ever fetch/update in its entirely. It's a completely different thing to have one you need to join on sub-values thereof.