I have a poll which has an undefined number of options (it can have only 2 options, but it can also have 10 or 20 or more options to choose from). I need to store the current vote count in MySQL table. I can't think of a centralized way of storing them except:
Create a field vote_count and store a serialized array of voting options mapped to counts.
When new vote data comes in this field is read, unserialized, appropriate values are incremented, then field is written to. This needs 2 queries and there might be 5 or more votes incoming per second.
So I need a way to store voting counts for an unknown number of voting options and be able to quickly access it (I need up to date counts for every option displayed on the voting page) and quickly update it (when new votes come in). It has to be within MySQL table. There is no "upper" limit for the number of voting options.
The normative pattern for handling multi-valued attributes, or repeating values, is to add a second table.
Consider a purchase order that can have more than one line item on it. We represent the line items in a child table, with a foreign key to the parent in the purchase order table:
CREATE TABLE `purchase_order` (id int not null, foo varchar(200), ... );
CREATE TABLE `line_item` (id int not null, order_id int not null, ... );
ALTER TABLE `line_item` ADD FOREIGN KEY (order_id) REFERENCES order(id) ;
INSERT INTO purchase_order (id, foo) VALUES (101, 'bar');
INSERT INTO purchase_order (id, order_id) VALUES (783, 101);
INSERT INTO purchase_order (id, order_id) VALUES (784, 101);
INSERT INTO purchase_order (id, order_id) VALUES (785, 101);
We can get a count of the line items associated with a purchase order, like this:
SELECT COUNT(1)
FROM line_item
WHERE order_id = 101;
Or, we can get a count of line items for every purchase order, like this:
SELECT o.id, COUNT(l.id) AS count_line_itesm
FROM purchase_order o
LEFT
JOIN line_item l
ON l.order_id = o.id
GROUP BY o.id
In your case, what are the entities you need to represent (person, place, thing, concept or event; which can be uniquely identified and you need to store information about.
I'm having difficulty conceptualizing what entities it is you are need to represent.
poll -
poll_question - a single question on a given poll
poll_question_answer - a possible answer to a question to a given poll question
voter -
ballot - associated with one voter and one poll (?)
vote - the answer given to a particular poll question
Good database design comes from an understanding of the entities and the relationships, and developing a suitable model.
Can't you just have one table of questions, and another table of possible answers (multiple rows per question, as many as you want). Then either store the counts on the table of answers, or (better) have another table of actual entered answers (this way you can log the details of the person doing the answers, and easily use SUM / COUNT to work out how many votes each option has).
Related
I have two tables: Orders that contains available orders and ExecutorsOfferOffers that contains offers by concrete user for specific order:
The order can be in four statuses: accepted, canceled, finished. Inside ExecutorsOfferOffers we have history of rows when user can accept, reject and complete the order (field status).
At the same time table Orders also has status field to show the current status of order. I confused how to be, move executor_id as external key to Orders table among status. Or store them in ExecutorsOfferOffers. And retrieve the status the order by selecting onw row ordered by id from ExecutorsOfferOffers.
In this case I faced with problem when user can accept, then cancel order (insert two rows in ExecutorsOfferOffers with different statuses).
If I understand correctly:
ExecutorsOrderOffers contains the history of user requests to change the status of the order.
Orders contains the current status of the order.
One Order can have many ExecutorsOrderOffers.
They're not recording the same data.
This information is not necessarily the same. Just because a User requested an order be cancelled does not mean it is cancelled; someone might need to make a phone call or an API might need to be contacted. Perhaps you should leave the status decoupled.
This leaves more flexibility for the business logic to determine the relationship between ExecutorsOrderOffers and Orders.
Use a join table to record the Order status.
Status flags get messy. You have to remember to add them to every where clause, and they make indexing complicated. Instead, consider using a join table to record the status of an order.
-- One for each status.
create table AcceptedOrders (
Order_Id int not null
foreign key(Order_Id) references Orders(Id)
);
Add a timestamp to ExecutorsOrderOffers.
IDs are not a surrogate for timestamps, and you're probably going to want to know when a user made a change; add a Created_At timestamp.
Add an index on ExecutorsOrderOffers(Created_At, Orders_ID)
Index Created_At with Orders_ID in that order. This will cover searches and order by for Created_At as well as when combined with an Orders_ID.
The foreign key index already covers search by Orders_ID alone.
Now you can efficiently look up the latest user request to change the status of an order.
My database is called 'shopping' and it contains the following tables:
products (product_id, product_name, price, category_id)
product_category (category_id, cagtegory_name)
customers (customer_id, username, pass, fname, lname, email)
orders (order_id, order_date, product_id, customer_id)
Now I want to consider keeping records of each products stock levels.
i.e
product_id = 1
product_name = MICROSOFT Limited Edition Gears 5 Xbox One X, Tekken 7 & Project Cars 2 Bundle
price = 449.99
category_id = 2
stock _id = 1 ( references stock_id in product_stock table ) :-/ ?
I have considered THREE approaches to storing 'stock info' on products.
Approach a) Add a new Column in products table called 'stock_level' simple, and valid since stock level is entirely dependent on its primary key in this situation.
Approach b) Create a new table called 'product_stock' , with the columns 'stock_id, and stock_level'.
The confusion is arising in the logic here.
For some reason, having gone with approach b, I had made the primary key of product_stock table (stock_id) ALSO a foreign key, referencing back to the products table as:
product_stock.stock_id = products.product_id
i.e
product_stock.stock_id 1 REFERENCES BACK TO products.product_id 1
product_stock.stock_id 2 REFERENCES BACK TO products.product_id 2
etc etc
THE THIRD approach I thought about was keep the stock_id key as a Primary Key only, and sever the link back to Products table. Then in products, create a column called stock_id with is a FK referencing stock_id in product_stock table.
Which of the three approaches seems the best ? I for some reason, regret deleting the columns and relations set up which was giving me behavior as discussed in approach b.
The reason I liked approach b was because, if you hover over each stock_id key in product_stock, you can see instantly what product it relates to in the products table ( phpmyadmin ).
thoughts on this folks ?
Refer to question and read.
no need, its all on phpmyadmin and not required in this case.
refer to question.
As far as you explained, each product has only and only one stock value. The simplest way to proceed is to to store that information directly in a products table: option a) in your question.
Using a separated table would be useful if, for example, you were in a situation where you have several stores and you need to keep track of the stock level of each product in each store. You would then create a separated table, with a column to store the id of the product, another to store the id of the store, and a third column to store the level of this particular product in this particular stock.
Is it possible to restrict inserts by a subquery or something like else without having the same data in different columns of different tables?
My example, I have the following tables:
Products
- ProductID
- CompanyID
- ProductDescription
User
- UserID
- CompanyID
- UserDescription
Orders
- OrderID
- Date
- UserID
- ProductID
Each user belongs to a company, each product is made by a company and every company may order products of each other. The catch: a company may order a product only once per day.
So I would love to make a constrain in Orders to make the combination of Date, ProductID and User.CompanyID. Then I could just do the insert statement and catch the exception or use "insert ignore" to just avoid invalid data. This is just a simplified case. I often have this problem where I would love to create a constrain with a column of a referenced table without using a bunch of triggers.
Is that possible in any way or am I forced to do a select first, check the result and then do the inserts if everything is valid?
You may do it like this:
1. Add an CompanyID column in table Orders;
2. Create an unique index which is a combination of (CompanyID,Date,ProductID).
The point here is: using the Unique Constraint to prevent a company from ordering the same product on the same day.
If you don't want any redundant data, you may apply a transaction. Just something like this:
BEGIN;
IF
(SELECT CompanyID FROM User WHERE UserID = userid LOCK IN SHARE MODE)
NOT IN
(SELECT CompanyID FROM User WHERE UserID IN (SELECT UserID FROM Orders WHERE Date = date AND ProductID = productid LOCK IN SHARE MODE) LOCK IN SHARE MODE)
THEN
INSERT INTO Orders VALUES (...);
END IF;
COMMIT;
As you can see, the code above is ugly, and it must be a performance killer.
There isn't any information about company in your Orders table. If you want to satisfy your weird demand, you must pay, and that is the price.
In my opinion, a redundant CompanyID column is just fine. It makes everything much faster and easier. Systems those who want to run faster usually hold redundant data.
I have a table as such:
id entity_id first_year last_year sessions_attended age
1 2020 1996 2008 3 34.7
2 2024 1993 2005 2 45.1
3 ... ... ...
id is auto-increment primary key, and entity_id is a foreign key that must be unique for the table.
I have a query that calculates first and last year of attendance, and I want to be able to update this table with fresh data each time it is run, only updating the first and last year columns:
This is my insert/update for "first year":
insert into my_table (entity_id, first_year)
( select contact_id, #sd:= year(start_date)
from
( select contact_id, event_id, start_date from participations
join events on participations.event_id = events.id where events.event_type_id = 7
group by contact_id order by event_id ASC) as starter)
ON DUPLICATE KEY UPDATE first_year_85 = #sd;
I have one similar that does "last year", identical except for the target column and the order by.
The queries alone return the desired values, but I am having issues with the insert/update queries. When I run them, I end up with the same values for both fields (the correct first_year value).
Does anything stand out as the cause for this?
Anecdotal Note: This seems to work on MySQL 5.5.54, but when run on my local MariaDB, it just exhibits the above behavior...
Update:
Not my table design to dictate. This is a CRM that allows custom fields to be defined by end-users, I am populating the data via external queries.
The participations table holds all event registrations for all entity_ids, but the start dates are held in a separate events table, hence the join.
The variable is there because the ON DUPLICATE UPDATE will not accept a reference to the column without it.
Age is actually slightly more involved: It is age by the start date of the next active event of a certain type.
Fields are being "hard" updated as the values in this table are being pulled by in-CRM reports and searches, they need to be present, can't be dynamically calculated.
Since you have a 'natural' PK (entity_id), why have the id?
age? Are you going to have to change that column daily, or at least monthly? Not a good design. It would be better to have the constant birth_date in the table, then compute the ages in SELECT.
"calculates first and last year of attendance" -- This implies you have a table that lists all years of attendance (yoa)? If so, MAX(yoa) and MIN(yoa) would probably a better way to compute things.
One rarely needs #variables in queries.
Munch on my comments; come back for more thoughts after you provide a new query, SHOW CREATE TABLE, EXPLAIN, and some sample data.
I am working on an assignment and need your help with the following in SQL database:-
I have 3 tables
Product
LintItem
Invoice
LineItem is a bride table and I need to insert data into LineItem but it requires ProductID and InvoiceNumber.
In my case the Invoice table is emppty and it will be filled from the data that LineItem table passes.
The problem is how can I create an invoice before having the data from the lineItem table?
I am using these table for online shopping cart.
It's really hard for me to explain this problem. Hope you understand it, Thanks!
It sounds like you have a foreign key constraint forcing the existence of a Invoice record prior to inserting your line item records. It is hard to say exactly, based on the phrasing of your question but could be something like.
--Table variable to hold line items
DECLARE #lineItems TABLE
(
InvoiceNumber INT,
Quantity INT
)
INSERT INTO #lineitems VALUES(1,1)
INSERT INTO #lineitems VALUES(1,2)
--ADD INVOICE RECORD FIRST AND SUM Quantities etc....
INSERT INTO Invoice
SELECT InvoiceNumber,SUM(Quantity)
FROM #lineItems
GROUP BY InvoiceNumber
--NOW YOU CAN ADD LINE ITEMS
INSERT INTO LineItems SELECT * FROM #lineItems
This is a pattern you could use if that was your goal.
If you are wanting to insert these LineItems on the fly as the user is clicking Add from the webpage. I wouldn't use your LineItem SQL table for caching this way. Without knowing anything about your application it is hard to say but you really should be caching this data in the HTTP session or in the client as (array,json, local storage etc..). If you were to choose to do this as an SQL table just make a new LineItem without the constraints and then similarly per above you can use that table to insert into your LineItem table.