I am making an application for a restaurant.
For some food items, there are some add-ons available - e.g. Toppings for Pizza.
My current design for Order Table-
FoodId || AddOnId
If a customer opts for multiple addons for a single food item (say Topping and Cheese Dip for a Pizza), how am I gonna manage?
Solutions I thought of -
Ids separated by commas in AddOnId column (Bad idea i guess)
Saving Combinations of all addon as a different addon in Addon Master Table.
Making another Trans table for only Addon for ordered food item.
Please suggest.
PS - I searched a lot for a similar question but cudnt find one.
Your relationship works like this:
(1 Order) has (1 or more Food Items) which have (0 or more toppings).
The most detailed structure for this will be 3 tables (in addition to Food Item and Topping):
Order
Order to Food Item
Order to Food Item to Topping
Now, for some additional details. Let's start flushing out the tables with some fields...
Order
OrderId
Cashier
Server
OrderTime
Order to Food Item
OrderToFoodItemId
OrderId
FoodItemId
Size
BaseCost
Order to Food Item to Topping
OrderToFoodItemId
ToppingId
LeftRightOrWhole
Notice how much information you can now store about an order that is not dependent on anything except that particular order?
While it may appear to be more work to maintain more tables, the truth is that it structures your data, allowing you many added advantages... not the least of which is being able to more easily compose sophisticated reports.
You want to model two many-to-many realtionships by the sound of it.
i.e. Many products (food items) can belong to many orders, and many addons can belong to many products:
Orders
Id
Products
Id
OrderLines
Id
OrderId
ProductId
Addons
Id
ProductAddons
Id
ProductId
AddonId
Option 1 is certainly a bad idea as it breaks even first normal form.
why dont you go for many-to-many relationship.
situation: one food can have many toppings, and one toppings can be in many food.
you have a food table and a toppings table and another FoodToppings bridge table.
this is just a brief idea. expand the database with your requirement
You're right, first one is a bad idea, because it is not compliant with normal form of tables and it would be hard to maintain it (e.g. if you remove some addon you would need to parse strings to remove ids from each row - really slow).
Having table you have already there is nothing wrong, but the primary key of that table will be (foodId, addonId) and not foodId itself.
Alternatively you can add another "id" not to use compound primary key.
Related
I'm designing a REST API where you can search for data in different countries, but since you can search for the same thing, at the same time, in different countries (max 4), am I unsure of the best/correct way to do it.
This would work to start with to get data (I'm using cars as an example):
/api/uk,us,nl/car/123
That request could return different ids for the different countries (uk=1,us=2,nl=3), so what do I do when data is requested for those 3 countries?
For a nice structure I could get the data one at the time:
/api/uk/car/1
/api/us/car/2
/api/nl/car/3
But that is not very efficient since it hits the backend 3 times.
I could do this:
/api/car/?uk=1&us=2&nl=3
But that doesn't work very well if I want to add to that path:
/api/uk/car/1/owner
Because that would then turn into:
/api/car/owner/?uk=1&us=2&nl=3
Which doesn't look good.
Anyone got suggestions on how to structure this in a good way?
I answered a similar question before, so I will stick to that idea:
You have a set of elements -cars- and you want to filter it in some way. My advice is add any filter as a field. If the field is not present, then choose one country based on the locale of the client:
mydomain.com/api/v1/car?countries=uk,us,nl
This field should dissapear when you look for a specific car or its owner
mydomain.com/api/v1/car/1/owner
because the country is not needed (unless the car ID 1 is reused for each country)
Update:
I really did not expect the id of the car can be shared by several cars, an ID should be unique (like a primary key in a database). Then, it makes sense to keep the country parameter with the owner's search:
mydomain.com/api/v1/car/1/owner?countries=uk,us
This should return a list of people who own a car with the id 1... but for me this makes little sense as a functionality, in this search I'll only allow one country:
mydomain.com/api/v1/car/1/owner?country=uk
My question is a variation on one already asked and answered (TSQL Delete Using Inner Joins) but I have a different level of complexity and I couldn't see a solution to it.
My requirement is to delete Special Prices which haven't been accessed in 90 days. Special Prices are keyed on Customer ID and Product ID and the products have to matched to a Customer Order Detail table which also contains a Customer ID and a Product ID. I want to write one function that will look at the Special Price table for each Customer, compare each Product for that Customer with the Customer Order Detail table and if the Maximum Order Date is more than 90 days earlier than today, delete it from the Special Price table.
I know I can use a CURSOR (slow but effective) but would prefer to have a single query like the one in the TSQL Delete Using Inner Joins example. Any ideas and/or is more information required?
I cannot dig more on the situation of your system but i think and if it is ok for you, check MERGE STATEMENT, it might be a help instead of using cursors. check this Link MERGE STATEMENT
I'm trying to plan a NOSQL table schema. There are relationships in my data, but they are mostly what would be N:N in a relational db; there are very few normal 1:N relationships.
So in this case, I'm trying to create implicit relationships that will allow me to browse from both ends of the relationship. I'm using Azure Table Storage, so I understand that full-text searching isn't available; I can only retrieve an "object" by its Partition Key + Row Key combination.
So imagine I have a table called "People" and a table called "Hamburgers" and each object in the tables can be related to multiple objects in the other table. Hamburgers are eaten by many people, people each eat many hamburgers.
Since the relationship is probably weighted to the people side - i.e. there are more people per hamburger than vice-versa, I would handle this in the tables like this:
Hamburger Table
Partition Key: Only 1 partition
Row Key: Unique ID
People Table
Partition Key: Only 1 partition
Row Key: Unique ID
"Columns": an extra value for every hamburger the person eats
Hamburger-People Table
Partition Key: Hamburger Row Key
Row Key: People Row Key
This way, if I'm looking at a hamburger and want to see all the people that eat it, I can go to the Hamburger-People table and use my Hamburger's Row Key to get the partition of all the people that eat the hamburger.
If I'm at a person and want to see all the hamburgers he/she eats, I have the extra values with the Row Keys of the hamburgers the person eats.
When inserting data into the tables, if the data involves a hamburger/person relationship, I would insert both values in the proper tables, then create the Hamburger-People table. If I was trying to keep a duplicate-free list of hamburgers, I would need to search the Hamburger table first to make sure the hamburger wasn't already in there (like "Whopper" - if it's in there, I wouldn't insert it again). Then, I would need to go insert a row in the hamburger's existing partition in Hamburger-People table.
But for the most part, the no-duplicate requirement doesn't exist.
Is this a good best-practices approach to NOSQL schema, or am I going to run into problems later?
UPDATE
Also, I would like to be able to partition the data tables later, but I'm not sure how to do so with this structure; adding a 2nd partition to the hamburger table would require me to store an extra value in the hamburger-People table, and I'm not sure if that would start to be too complex.
Ok, nice questions and I think most of them are the ones each RDMBS developer face as soon as hits NoSQL world:
1. How to group the partitions?
To get the best of the partitions you need to think that the load of your database should be distributed across your servers, lets see what will happend with your approach
A person with Key "A" enters to the restaurant you will save it and his burger, which is a Classic Tasty (Key "T") the person record goes to the server X and the Burger goes to server Y, now a new customer goes enters with the Key "B", and wants something different, a burger "W", again the person goes to server X and the burguer to server X, this time the server X is getting all the load, if you repeat this you'll see that the server X becomes a bottle neck, because 75% of the records are going there (all the people and 50% of the burgers), that will create some problems with your load. But... the problem will be better when you try to query because all the queries will hit the server X.
To solve this you could use the key of the person as part of the partition for the relationship, so the person will be partitioned in the same server of the burguers relationship, this way your workload will be balanced and you wont have any problems if one of the servers goes down (the person and hamburguers will be "lost" together), this will be a consistence "inconsistency"
2. Should I use a "relationship" in a NoSQL database?
Remember that NoSQL means that you are granted to duplicate information anytime your problem requires a solution to avoid "overqueries", so, if you can store the information that will be commonly queried together you will avoid a roundtrip to the database. So, if you store a "transaction" instead of "person and burguers" you will get a better performance and avoid some hits to the database, lets do an example of real data with your approach and compare it with "my" approach:
Joe Black comes to the restaurant and ask for a tasty, here you will do the following transactions:
Create a Joe Black record
Create a Burguer transaction record
if you want to list your daily transactions you will need to:
Get all the records from the day in the "table" person-burguer, then go to the person "table" and retrieve the name of the customers and now, go to the hamburguer records and retrieve their names. (you wont be able to do cross-table queries because some records could be in one server and others in the second server)
Ok, what if you create a table "transactions" and store in there the following json:
{ custid: "AAABCCC",
name: "Joe", lastName: "Black",
date: "2012/07/07",
order: {
code: "Burger0001",
name: "Tasty",
price: 3.5
}
}
I know you will have several records with the same "tasty" description, that's desnormalization which is very useful when you approach NoSQL solutions to these type of problems, now, how many transactions did you create to store the information to the database? just one! wow... and how many queries will you need to retrieve the information at the end of the day? again... just one, it will create some problems, but will save you a lot of work too, like... could you reprint the order easily? (yes you can!) what if the name of the customer changes? is that even possible?
I hope this help you some way,
I'm the creator of http://djondb.com so I think that having inside knowledge gives me a different approach to the problems according to what the database will be able to do, but I'm not aware of how azure will handle the queries if you are not able to query the document values and just the row keys, but anyway I hope this gives you an insight.
I have created an adaptation of the 'Goods' database that includes a quote feature. The user selects the customer (customer table), Product (product table), qty, discount ect.
The chosen entities then get saved to the quotes table and there is a 'print' function on form.
Whilst the information can be saved and the quote prints via a quote report, I'm having major difficulty in finding a way to add multiple products to a single quote.
The main objective is to be able to select various products and add their total price (product after addition of qty, discount) to a SUB TOTAL
Quote total is therefore the formula Tax+Shipping+SubTotal
any takers? :)
Hi guys,
Thanks for the response I really appreciate it. As for tax and shipping, they are just added in the form and are not pushed from anywhere else in the database. Its simply a type in form and display on report sort of thing. As you said in the answer, HansUp, the salesperson will compute it seperately and just input it.
As for tax, products will be shiped globally so the tax/vat shall be computed seperately also.
Also, each table DOES have its own unique ID.
More to the point of having QuoteProducts. I can't seem to get my head around it! Are you saying that whatever products are chosen in QuoteProducts will create a QuoteProd_ID and then that ID's total price will therefore be added to the Quote?
I tried making a subform before but through the 'multiple records' form but obviously every selection made its own ID. Is there any way you could elaborate on the Quote products part and how it allows multiple records to store to one ID? Without understanding it i'm pretty much useless.
In addition, how the multiple records are then added up to make the subtotal also baffles me. Is that done in the Quote form?
Edit 2
HALLELUJAH.
It works! I created a sum in a textbox on the footer of the subform and then pushed that into subtotal :)
I do have one slight issue:
I made a lookup&relationship for the ListPrice. I don't think its the correct way to do it as it comes up with the price of every light (i.e 10 products priced £10, £10 shows up ten times in dropdown).
Can you guys help?
List Price Problem
here's what i've tried:
1) Create >Client>Query Design
2) Show Products, QuoteDetails. For some reason, it automtically comes up with ListPrice, ProductID (as it should) and Product Name linked to ID in Products
3) Delete links with ListPrice and ProductName.
4) Show all in quoteDetails (*)
5) Create Multiple Items form
Doesnt work! What am I doing wrong?
I'm extremely grateful for both your help. If I can do anything, just shout.
Ryan
In addition to HansUp's stellar answer, you might be interested in DatabaseAnswers.org. They have a number of data models for free that might provide additional insight to your situation and possibly serve as inspiration for future projects you may encounter.
Edit 1
Forget about the form and report for a moment - they are important but not as important as the data and how you store the data.
In your current design, you have a quotes table presumably with an autonumber key field. For the purposes of this answer, this field is named Quote_ID.
The quotes table, as HansUp suggested, should store information such as the Customer_ID, Employee_ID, OrderDate and perhaps even a reference to a BillingAddress and ShippingAddress.
The quotes table SHOULD NOT store anything about the products that the customer has ordered as part of this quote.
Instead, this information should be stored in a table called QuoteProducts or QuoteDetails.
It's structure would look something like the following:
QuoteDetails_ID --> Primary Key of the table (autonumber field)
Quote_ID --> Foreign key back to the Quotes table
Product_ID --> Foreign key back to Products table
Quantity
UnitPrice
You may also want to consider a field for tax and a separate field for shipping per line item on the quote. You will inevitably run into situations where certain items are taxable in some locations and not others, etc.
This design allows a particular quote to have any number of products assigned to the quote.
Returning to your form \ reports, you would need to change your existing forms and reports to accomodate this new table design. Typically one would use a main form for the quote itself, and then a subform for the quote details (item, price, quantity, etc).
To get the quote total, you would sum the items in QUoteDetails for a particular Quote_ID.
You may also want to check out the Northwind sample database from Microsoft. From what I recall Northwind had a sample Orders system that might help make these ideas more concrete for you by seeing a working example.
For the first 3 tables mentioned in your comment, each should have a primary key: Customers, customer_id; products, product_id; and employees, employee_id.
The quotes table will have its own primary key, quote_id, and will store customer_id and employee_id as foreign keys. (I'm assuming you want employee_id to record which customer representative/salesperson created the quote.) You may also decide to include additional attributes for each quote; date and time quote prepared, for example.
The products offered for quotes will be stored in a junction table, QuoteProducts. It will have foreign keys for quote_id and product_id, with one row for each product offered in the quote. This is also where you can store the attributes quantity and discount. An additional field, unit_price, can allow you to store the product price which was effective at the time the quote was prepared ... which would be useful in case product prices change over time. I don't know whether tax should be included in this table (see below).
I also don't know how to address shipping. If all the products associated with a quote are intended to be delivered in one shipment, shipping cost could be an attribute of the quotes table. I don't know how you intend to derive that value. Seems like it might be determined by shipping method, distance, and weight. If you have the salesperson compute that value separately, and then input the value, consider how to handle the case where the product selection changes after the shipping fee has been entered.
That design is somewhat simplistic, but might be sufficient for the situation you described. However, it could get more complex. For example, if you decide to maintain a history of product price changes, you would be better off to build in provisions for that now. Also, I have no idea how tax applies in your situation --- whether it's a single rate applied to all products, varies by customer location, varies by type of customer, and/or varies by product. Your business rules for taxes will need to be accommodated in the schema design.
However, if that design works for you (test it by entering dummy data into the tables without using a form), you could create a form based on quotes with a subform based on QuoteProducts. With quote_id as the link master/child property, the subform will allow you to view all products associated with the main form's current quote_id. You can use the subform to add, remove, and/or edit products associated with that quote.
Not much I can say about the report. There is a lot of uncertainty in the preceding description. However, if your data base design allows you to build a workable form/subform, it should also support a query which gathers the same data. Use that query as the record source for the report. And use the report's sorting and grouping features to create the quote grand total.
Edit: With the main form/ subform approach, each new row in the subform should "inherit" the quote_id value of the current record in the main form. You ensure that happens by setting the link master/child properties to quote_id. Crystal Long explains that in more detail in chapter 5 of Access Basics by Crystal: PDF file. Scroll down to the heading Creating a Main Form and Subform on page 24.
Edit2: Your strategy may include storing Products.ListPrice in QuoteDetails.ListPrice. That would be useful to record the current ListPrice offered for a quote. If so, you can fetch ListPrice from Products and store it in QuoteDetails when you select the ProductID for a row in the subform. You can do that with VBA code in the after update event of the control which is bound to the ProductID field. So if that control is a combo box named cboProductID and the subform control bound to the QuoteDetails ListPrice field is a text box named txtListPrice, use code like this for cboProductID after update:
Me.txtListPrice = DLookup("ListPrice", "Products", "ProductID = " _
& Me.cboProductID)
That suggestion assumes the Products and QuoteDetails tables both include a ProductID field and its data type is numeric. And cboProductID has ProductID as its bound field and uses a query as its RowSource similar to this:
SELECT ProductID, ProductName
FROM Products
ORDER BY ProductName;
I have two tables: "Stock Master" and "Stock In", how do I create a many-to-one relationship between them? "Stock In" records many different stocks by different dates and quantities, but "Stock Master" must show and combine the same stocks with their quantities into one, and must function as first-in first-out.
It doesn't sound like a many-to-one is what you really need.
If I understand correctly, you have inventory coming in at different times of different types. You want to record what has come in, you want to see how much of a specific type you have, and you want to be able to identify oldest received batch so you can prioritise that for shipping.
Vastly simplified, you'd just have that one table recording received shipments with a time and date received column which you can call WHERE clauses on to determine which entry is the oldest and should therefore be shipped.
You don't need a table as such for aggregating inventory (ignoring options like materialized views and such for now). Just sum the quantity column; group by product type.
If you want to create a view in Postgresql (as it appears you do from your comment to JosefAssad's advice), as in just about any other SQL db, use something like:
CREATE VIEW Stockmaster (prodid, total)
AS SELECT prodid, SUM(quantity)
FROM Stockin
GROUP BY prodid
Unless I'm missing something here, you would handle this by using the appropriate primary/foreign key relationships.