Site-wide comments with different type of pages and special requirements - sql

I am interested in designing the database (well, I'm only concerned about one table really) for a site with the following requirements:
There is an items page, which lists items. items.xyz?id=t displays the item with ID t. I need the IDs of the items to be consecutive. The first item has ID 1, the second ID 2 and so on. Each item page has comments on that item.
There are other pages, such as objects, where objects.xyz?id=t displays the object with ID t. The IDs here need not necessarily be consecutive (and they can overlap with item IDs, but it's ok if you suggest something that forces them not to overlap). These also have comments.
My question is how to design the Comments table? If I have an EntityID in it that represents the page the comment should be displayed on (be it an item page or an object page), then should I make it so that the ItemID never overlaps the ObjectID by making all ObjectID start from, say, 109 and using a GUID table? (The ItemIDs increase very slowly). Is this acceptable practice?
Right now I'm doing it by having a bunch of nullable boolean fields in each comment: IsItem, IsObjectType1, IsObjectType2, ..., which allows me to know where each comment should be displayed. This isn't so bad since I only have a few objects, but it seems like an ugly hack.
What is the best way to go about this?

I see three solutions (assuming it is impossible or undesired to put Pages and Objects in one table). Either:
Tell the comment which it belongs to by giving it two columns: PageId and ObjectId.
That way you can also give these columns foreign keys to the respective tables and add proper indexes.
Introduce a table 'Entity' that has a unique id, a PageId and an ObjectId. Either columns are optional off course, exactly one of them must be filled, not 0 or both.
This way, you move all the potential garbage of having separate entities to this table, not polluting the Comments table, which should contain just comments. You isolate the mess.
Create a link table between Comments and Items and another table between Comments and Objects. Items and Objects are completely unrelated, and you don't have to pollute the Comments table with a lot of NULL values in multiple columns. When you create a comment, you decide if it links to an Item or an Object by inserting a link in either ItemComments or ObjectComments. Reading comments for an item or object is a matter of two simple joins.
The comments table can then contain only a single EntityId that refers to the Id in the Entity table.
The big advantage to this approach is twofold:
a) You can link other things to the same table too, whichout much hassle.
b) You can add other kinds of Entities and they will automatically support Comments and other things you might add, as mentioned in a).

Related

Connecting one foreign key to multiple tables (primary keys)

I am developing an application for making quotations. First you make cost break down (or calculation) and upon that result you add item to quotation. The problem is that i have many product, so each category of a product will have its own cost break down form with different parameters to be filled in. If I will have only one table for cost breakdown, then it will be huge (a lot of fields in table). I have a feeling that this is not the right approach. So I came up with diagram below:
Is this solution even possible, or I must have "N" (if I have N-tables) different FK for each cost break down table? Do you have any better solutions?
I have another question if my linking table "Quotation_QtnDetail" is necessary?
It would be possible to store a reference to a particular value in one of these tables by having a CalculationType column indicating which table the record is in, along with a generic reference ID column (containing the ID of the relevant record). For example, if you were storing a CalcId of 123 and a CalculationType of 2, this would point to the record with ID 123 in the Calc2 table.
The downside to doing this is you're going to lose the ability to validate your data using FK constraints, and it will also make joins to your calculation tables a bit more complicated.
Regarding the Quotation_QtnDetail table, unless a QtnDetail record could ever be linked to multiple Quotation records, there is no need for this extra linking table. Instead, just link it directly by adding a QtnId column to the QtnDetail table. Similarly, you may also be able to remove the Calc_QtnItm table if an item is only ever linked to a single calculation record.

Is a two table solution a performant and scalable solution to implement tagging in Postgres 9.5?

Background
I work for a real estate technology company. An upcoming project involves building out functionality to allow users to affix tags/labels (plural) to a MLS listing (real estate property). The second requirement is to allow a user to search by one or more tags. We won't be dealing with keeping track of counts or building word clouds or anything like that.
Solutions Researched
I found this SO Q&A and think the solution is pretty straightforward and have attempted to adapt some ideas from it below. Also, I understand that JSONB support is much better in 9.5 and it may be a possibility. If you have any insight here I'd love to hear your thoughts as well in an answer.
Attempted Solution
Table: Tags
Columns: ID, OwnerID, TagName, CreatedDate
Table: TaggedItems
Columns: ID, TagID (references above), PropertyID, CreatedDate, (Possibly some denormalized data to assist with presenting search results; property name, original listor, etc.)
Inserting new tags should be straightforward. Searching tags should also be straightforward since the user will select one or multiple tags from a searchable dropdown, thus affording me access to the actual TagID which I can use to query the TaggedItems table. When showing the full profile view for a listing, I can use it's PropertyID and the UserID to query my tables for the existence of one or more Tags to display in the view.
Edit: It's probably worth noting that we don't keep an entire database of properties, we access them via an API partner; hence the two table solution and not 3.
If you want to Nth normalize you would actually use 3 tables.
1 Property/Listing
2 Tags
3 CrossReferenceBetween the Two
The 3rd table creates a many to many relationship between the other 2 tables.
In this case only the 3 rd table would carry both the tagid and the property.
Going with 2 tables if fine too depending on how large of use you have as a small string won't bloat your databse too much.
I would say that it is strongly preferable to separate the tags to a separate table when you need to do lookups and more on it. Otherwise you have to have a delimited list which then what happens if a user injects a delimiter into their tag value? Also how do you plan on searching the delimited list? You will constantly expand that to a table or use regex and the regex might give you false positives as "some" will match "some" and "something" depending on how you write your code.......

database design, items and orders tables

I was just after some input on database design. I have two tables, Orders and Items.
The items table is going to be a list of items that can be used on multiple orders, each item has an id
The way i thought to do it at the moment, was in the order to put an array of comma seperated ids for each item in the order.
does that sound like the best way?
also im using linq to entity framework and i dont think id be able to create a relationship between the tables, but i dont think one is needed anyway is there, since the items are not unique to an order
Thanks for any advice
The way I thought to do it at the moment, was in the order to put an array of comma separated ids for each item in the order. Does that sound like the best way?
Absolutely not - It will be MUCH more difficult in SQL to determine which orders contain a particular item, enumerate the items (to get a total, for example), and to add/remove items from an order.
A much better way would be to create an OrderItem table, which has a foreign key back to Order and Item and any other attributes relating to the item in that order - quantity, discount, comments, etc.
As far as EF goes, it will probably create a third entity (OrderItem) that will "link" the two tables. If you don't add any extra properties (which you probably should) then EF will probably create it as a many-to-many relationship between the Order and Item entities.
As far as I have understood from your question (it is not very clear), every Order can have multiple Items and every Item can be used in multiple orders. If this is what you want, you have a many to many relationship, that must be resolved using an intersection entity. This intersection entity has 2 foreign keys, one for item and one for order. Using it, you can identify what items are in a certain order and what orders need a certain item.
As my explanation is very short and very sloppy, I will recommend you the following references:
http://sd271.k12.id.us/lchs/faculty/bkeylon/Oracle/database_design/section5/dd_s05_l03.pdf
Resolve many to many relationship
Also, you proposed design is very bad, as it breaks the first normal form: no attribute can have multiple values. You shoud try to build databases at least in third normal form.
Regarding the database design, you would usually create a third table - ORDER_ITEMS - linking the two tables, containing columns (foreign keys) for order id and item id. You might also want to include a column for quantity.

sql table name, item or items

I name my tables according to what the row describes. So if it describes one comment in one row, I name it "comment".
I have a table with id, created_at, updated_at, name, description, quantity, sample. I am unsure what to name it due to "quantity". I think it can be seen in two ways.
The table describes one specific kind of item. There are x number of this one kind of item. As such the table should be named "item". Similar to fish vs fishes.
The table describes many items in each row due to quantity. As such it should be named "items". The caveat is that there can be 0 or 1 of the item.
I've also entertained the idea that quantity may be describing a subtly different entity and belongs in a separate table.
Ultimately, I think this is a style thing, but I think you should be consistent across your tables rather than trying to come up with a different concept table by table.
Personally I prefer singular because of the inconsistencies of pluralizing words, but a lot of people prefer plural because the table seems to be a collection of things.
In your example, though, I'm not sure why the presence of "quantity" as one of your columns would factor in. A table called "animal" could have a "number_of_legs" column, but I don't think that would change the way you think about the overall table of animals.
Item.
Each row contains a kind of item. A property of the item is the quantity. If each specific item had a separate row, and included a column such as SerialNumber, then Items would be appropriate.
Each row is not exactly describing an item, but an item bundle, right? Either way, don't overthink it.
From your question I would use 'item' because it's gonna be more similar to your other tables.

How to add user customized data to database?

I am trying to design a sqlite database that will store notes. Each of these notes will have common fields like title, due date, details, priority, and completed.
In addition though, I would like to add data for more specialized notes like price for shopping list items and author/publisher data for books.
I also want to have a few general purpose fields that users can fill with whatever text data they want.
How can I design my database table in this case?
I could just have a field for each piece of data for every note, but that would waste a lot of fields and I'd like to have other options and suggestions.
There are several standard approaches you could use for solving this situation.
You could create separate tables for each kind of note, copying over the common columns in each case. this would be easy but it would make it difficult to query over all notes.
You could create one large table with many columns and some kind of type field which would let you know which type of note it is (and therefore which subset of columns to use)
CREATE TABLE NOTE ( ID int PRIMARY KEY, NOTE_TYPE int, DUEDATE datetime, ...more common fields, price NUMBER NULL, author VARCHAR(100) NULL,.. more specific fields)
you could break your tables up into a inheritance relationship something like this:
CREATE TABLE NOTE ( ID int PRIMARY KEY, NOTE_TYPE int, DUEDATE datetime, ...more common fields);
CREATE TABLE SHOPPINGLITITEM (ID int PRIMARY KEY, NOTE_ID int FORIENKEY NOTE.ID, price number ... more shopping list item fields)
Option 1 would be easy to implement but would involve lots of mostly redundant table definitions.
Option 2 would be easy to create and easy to write queries on but would be space inefficient
And option 3 would be more space efficient and less redundant but would possibly have slower queries because of all the foreign keys.
This is the typical set of trade-offs for modeling these kinds of relationships in SQL, any of these solutions could be appropriate for use case depending non your performance requirements.
You could create something like a custom_field table. It gets pretty messy once you start to normalize.
So you have your note table with it's common fields.
Now add:
dynamic_note_field
id label
1 publisher
2 color
3 size
dynamic_note_field_data
id dynamic_note_field_id value
1 1 Penguin
2 1 Marvel
3 2 Red
Finally, you can relate instances of your data with the fields they use through
note_dynamic_note_field_data
note_id dynamic_note_field_data_id
1 1
1 3
2 2
So now we've said: note_id 1 has two additional fields. The first one has a value "Penguin" and represents a publisher. The second one has a value of "Red" and represents a color.
So what's the point of normalizing it this far?
You're not wasting space adding fields to every item (you relate a note with it's additional dynamic field via the m2m table).
You're not storing redundant labels (you may continue to store redundant data however as the same publisher is likely to appear many times... this aspect is extremely subjective. If you want rich data about your publishers you typically want to take the step of turning them into their own entity rather than an ad-hoc string. Be careful when making this leap because it adds an extra level of hairiness to the db. Evaluate the use case accordingly.
The dynamic_note_field acts as your data definition. If you're interested in answering a question such as "what are the additional fields I've created" this lets you do it easily without searching all of your dynamic_note_field_data. Eventually, you might add extra info to this table such as a type field. I like to create this separation off the bat, but that might be a violation of the YAGNI principle in your case.
Disadvantages:
It's not too bad to search for all notes that have a publisher, where that publisher is "Penguin".
What's tricky is something like "Find any note with a value of 'Penguin' in any field". You don't know up front which field's your searching. At this point you're better off with a separate index that's generated alongside your normalized db data which acts as the point of truth. Again, the nice thing about normalization is that you maintain the data in a very lossless, non-destructive state.
For data you want to store but does not have to be searchable, another option is to serialize it to/from JSON and store it in a TEXT column. This gives you arbitrary structure, but you cannot readily query against those values.
Yet another option is to dump SQLite and go with an object database. I seem to recall there are one or two working for Android. I have not tried any of these, however.
Just create a small table which contains the common fields of all your notes.
Then a table for each class of special notes you have, that that contains all the extra fiels plus a reference on your first table.
For each note you will enter, you create a row in your main table (that contains the common fields) and a row in your extra table that contains the extra fields, and a reference to the row in your main table.
Then you will just have to make a join in you request.
With this solution :
1)you have a safe design (can't access fields that are not part of your note)
2)your db will be optimized