I'm creating an app that will search a table called tags for events tagged with those tags. There will be two tables: tags and events, and when a user searches for something, the app searches the tags table and then displays information for the relevant information from the events table.
This is the flow of how the application will search and display data:
User searches ->
SQL search on tags table ->
using tag_ids found, search for relevant events on events table ->
display event data
Am I thinking about this the correct way? I have a feeling I might not be. I don't want to store each of the tag_ids in columns named tag_id_1, tag_id_2, etc. on the events table, and I don't want to limit the number of tags that a user can have attached to an event. However, I don't want to rely on my application to do major processing of the SQL, so I don't want to store the tags as a JSON object in the table either. Is this possible, or will I have to change how I search?
You have here an N:N relationship. There are multiple types of tags that can be added to multiple different events. You need to create another table to link those together: a tags_per_event table, for example.
In the tags table you store only information about the tags themselves (id, description..). In the events table you only describe events (id, description, source...). Finally, in the tags_per_event table you have one row for each tag for each event. For each row, you will have the ID of the tag and the ID of the event. When you lookup the information, you need to join the 3 table in order to get all the information about which tags were assigned to which event and what is the information you have on those (adding descriptions and such).
IMHO you need one more table. You already have TAGS and EVENTS, but TAGS shouldn't be included in the EVENTS table, so create a TAGS_EVENTS table, with one row for every TAG_ID and EVENT_ID.
TAGS TABLE
ID | NAME
1 | sql
2 | oracle
EVENTS TABLE
ID | TYPE
1 | Question asked
2 | Question asked
TAGS_EVENTS TABLE
EVENT_ID | TAG_ID
1 | 1
1 | 2
2 | 2
EXPLANATION:
EVENT 1: Question asked with tags "sql" and "oracle"
EVENT 2: Question asked with tag "oracle"
Related
I hope I explain this adequately.
I have a series of Google Sheets with data from an Airtable database. Several of the fields are stringified arrays with recordIds to another table.
These fields can have between 0 and n - comma separated values.
I run a create/overwrite table SELECT statement to create native BigQuery tables for reporting. This works great.
Now I need to add the recordIds to a Repeated field.
I've manually written to a repeated field using:
INSERT INTO `robotic-vista-339622.Insurly_dataset.zzPOLICYTEST` (policyID, locations, carrier)
VALUES ('12334556',[STRUCT('recordId1'),STRUCT('recordId2')], 'name of policy');
However, I need to know how I to do this using SELECT statement rather than INSERT. I also need to know how to do this if you do not know the number of recordIds that have been retrieved from Airtable. One record could have none and another record could have 10 or more.
Any given sheet will look like the following, where "locations" contains the recordIds I want to add to a repeated field.
SHEETNAME: POLICIES
|policyId |carrier | locations |
|-----------|-----------|---------------------------------|
|recrTkk |Workman's | |
|rec45Yui |Workman's |recL45x32,recQz70,recPrjE3x |
|recQb17y |ABC Co. |rec5yUlt,recIrW34 |
In the above, the first row/record has no location Id's. And then three and two on the subsequent rows/records.
Any help is appreciated.
Thanks.
I'm unsure if answering my own question is the correct way to show that it was solved... but here is what it took.
I create a Native table in BigQuery. the field for locations is a string, mode repeated.
Then I just run an overwrite table SELECT statement.
SELECT recordId,Name, Amount, SPLIT(locations) as locations FROM `projectid.datasetid.googlesheetsdatatable`;
Tested and I run linked queries on the locations with unnest.
heres the situation. I have a table called as maps coordinates the schema is like below:
map_coordinates:
item | item_id | latitude | longitude
The idea is that this table contains a list of coordinates of different items, they could be a note, a classifieds post, an event etc. I want to be able to set it up so I have a result set as below:
item | name of item | latitude | longitude
Consider that all events, classifieds and notes are in separate tables. How could I be able to set this up as I need to show all the coordinates on a google maps along with the name of the element i.e if its a classifieds - the title of the ad, an event the title of it etc without having to make alot of sql queries.
I have the code to show it on the map - I just need to grab the details as such. Or do I have to redo my database design here?
========================
EDIT
Actually I have a number of tables in my database such as notes, classifieds and events etc. The point is that an item in the maps_coordinates table refers to the type of the element i.e if its a note or event and teh item_id is the actual id of that event. I don't want to get stuck with using joins here because that would involve alot of tables. Besides I just need to grab basic information as in just the title to help in populating the map so when I hover over the individual markers I don't have to make an ajax call just to show basic information of the element at the marker.
The other tables have their own definitions but all of them have a similar title field and it is this title field I wish to show in the same tuple as the coordinates. Or should I denormalize my tables here and have a duplicate entry for title sin the map_coordinates?
You can do this by creating a view that combines each of the common elements from the separate tables. In your example note, classifieds post, event, etc.
CREATE VIEW viewCommonElements
AS
SELECT
100 as DataType,
NoteId as ElementId,
NoteName as ElementName
FROM Notes
UNION
SELECT
200 as DataType,
Classified_Post_Id as ElementId,
Post_Description as ElementName
FROM Classified_Posts
UNION
SELECT
300 as DataType,
EventId as ElementId,
EventName as ElementName
FROM Events
Simply add a new DataType for each table you have that you want included in your common elements. You can now set up one query that joins to the viewCommonElements view.
If a new element is created later on just modify the view and add a union select block giving it a unique datatype. You can use the DataType to distinguish the different common elements from each other.
I've used this method several times to harmonize dis-similar but common data.
Yes, basically your DB design is not good. Try it like this:
map_coordinates:
item | item_id | item_type | item_name | latitude | longitude
and use a lookup table for item_types.
You say "The idea is that this table contains a list of coordinates of different items, they could be a note, a classifieds post, an event etc.". Does this mean that there are different tables for different items? If so, a denormalized table with all the lookup information is likely your best bet. If not, it's just a matter of JOINing the two tables.
So here's the basic problem: I'd like to be able to store various fields in a database. These can be short textfields (maybe 150 characters max, probably more like 50 in general) and long textfields (something that can store a whole page full of text). Ideally more types can be added later on.
These fields are group by common field_group ids, and their type shouldn't really have anything to do with categorization.
So what's the best way to represent this in MySQL? One table with a short_text and long_text columns of differing types, one of which is to be NULL? Or is there a more elegant solution?
(I'd like this to be primarily driven by ease to select all fields with a given field_group_id.)
Clarification
I'm essentially attempting to allow users to create their own tables, but without actually creating tables.
So you'd have a 'Book' field group, which would have the fields 'Name' (short text), 'Summary' (long text). Then you would be able to create entries into that book. I realize that this is essentially the whole point of MySQL, but I need to have a LOT of these and don't want users creating whole tables in my database.
What you are looking for is called an EAV. With an EAV model you can build any freaking database in the world with only inserts. But it's really horrible for a lot of reasons but yours sounds so looney-tunes, it could work.
Build an Entity table
In here you'd list
Car
Person
Plant
Build an Attribute Table.
Here you'd list the PK from Entity and the list of attributes.
I'll use the word instead of a number PK.
Car | Engine Cylinders
Car | Doors
Car | Make
Person | First Name
Person | Last Name
then in a third table you'd list the actual values for each one, again using the words but you'd have numbers.
Car | Engine Cylinders | 4
Car | Doors | 4
Car | Make | Honda
Person | First Name | Stephanie
Person | Last Name | Page
If you want to get tricky instead on one column for value you could have 4 columns
a number
a varchar
a date
a clob
then in the Attribute table you could add a column that says which column to put the data.
If you plan on this database being "Multitenent" you'll need to add an OWNER table as the parent of the entity table, so you and I could both have a Car entity.
But this SUCKS to query, SUCKS to index, SUCKS to use for anything else but a toy app.
I don't know exactly what you mean by "field group", but if the information (short text, long text) all belongs to a certain entry, you can create a single table and include all those columns.
Say you have a bunch of books with a title and a summary:
table: `books`
- id, int(11) // unique for each book
- title, varchar(255)
- writer, varchar(50)
- summary, text
- etc
Fields that don't necessarily need to be set can be set to NULL by default.
To retrieve the information, simply select all the fields:
SELECT * FROM books WHERE id = 1
Or some of the fields:
SELECT title, writer FROM books ORDER BY title ASC
I would like a bit more clarification on the toxi method of storing tags in a database – mentioned elsewhere on SO.
The database schema is:
Table: Item
Columns: ItemID, Title, Content
Table: Tag
Columns: TagID, Title
Table: ItemTag
Columns: ItemID, TagID
This is probably a stupid question (but I don't know the answer)... Should each entry, in the Table Tag, have a unique title. i.e. I only store a tag once or store it every time I use it?
To illustrate, which of the two tables below should I end up with:
TagID Title
1 Fish
2 Cat
3 Dog
or
TagID Title
1 Fish
2 Fish
3 Cat
4 Fish
5 Dog
6 Cat
If using the first table, before entering the tag I would first have to run and sql statement to find out if it exists, correct?
Any help will be appreciated. I had my fingers burn recently due to hacking together and indexing, want to start getting the basics correct.
The basics are that you need to store tags like you're showing in first case. It's good for checking if tag exists (since in second case for existing tags your db would return as many rows as there are those appearances of tag) and good for retrieving items by tag (select item id by one tag id is better than selecting item ids by a set of tag_id which has same representational meaning).
If you had burnt your fingers because of indexing - you should always check how query is being executed (for mysql it's EXPLAIN/DESCRIBE SELECT).
If "Fish" and "Fish" are the same tag, you should probably have it only once in your Tag table.
So, I would go with your first solution -- which, indeed, implies doing a select before your insert, to determine whether the tag already exists or not ; and, if it exists, using its already existing TagID for the link between the item and the tag, in the ItemTag table.
Actually, this is the reason for which the ItemTag exists : it is an association table, which stores correspondances between items and tag : for each item, you can have several tags, and, for each tag, you can have several items.
This will also, btw, make things easier to get a list of items that are attached to a specific tag.
You should have the tags only once in the tag table; the whole point of the ItemTag table is to provide you with an n:m association (each item having multiple tags, and each tag belonging to multiple items).
If you would repeat the tag titles, you could simplify the structure by having the Tag table use ItemIDs right away, not tag IDs.
I'm currently working on a project where I need to save data depending upon the active no. of items.
Its like..
Stores can have n no of items which can be dynamically added or reduced from admin back-end. Each item can either be activated or deactivated. NO problem.
But I need to manage/save these dynamic n no. of items in a table for each store. I'm not able to decide on the table schema.
Any help will be highly appreciated.
I suggest a standard many-to-many relationship using a middle table. So you would use 3 tables:
StoresTable: the list of stores
ItemsTable: the list of items
StoreItemsTable: a list of items-in-stores, each row will have a foreign key to both the stores table and the items table
Hope that helps.
your problem is actually not that hard if you use a different approach.
A store can have a number of items. So basically Susi's store has 1 item, but suddenly she wants 2, and you would like to add a column. This is very difficult if she suddenly wants to add 2000 items.
The best approach would be to use a store table (which has the name of the store, the date it was created and a primary key) and a items table. You can then add items as entries to the table and link them to the store via the stores primary key.
An example:
Store table:
PK Name Owner
1 Sunshine Store Susi
2 Moonstore Harald
Item table:
PK Name Store_id Price
1 Candle 1 2.44
2 Table 1 51.44
3 Chair 2 6.55
This allows you to add as many items to any store you want. The Store_id is called a Foreign Key in this example, because it links the items to the store. You can then use SQL commands to select the items, e.g.
"Select * from ITEMS where Store_id = 1;"
and get all of Susi's items as an answer.
Good luck!
i think you use active column and use that active bit for every purpose because that's very good for future in other transaction too.