There is a factory with 15 production lines. Each production line, every day gets its own table and needs to fill in efficiency measurements every hour. Table consists of columns (time periods) and categories with sub categories which makes it around 80 rows. Here is an example:
Could you give me any suggestions with database design ?
Requirements:
Server needs to get all table data for specific day fast.
Server needs to retrieve a specific cell (by line number, date, time period and subcategory) fast.
create table metric
( -- a thing to track
metricNum int auto_increment primary key, -- 1,2,3 etc
metricName varchar(200) -- ie: "Splat & spild", etc
);
create table efficiency
( -- all data for all lines for all time
id int auto_increment primary key,
lineNum int not null,
theDate day not null,
metricNum int not null,
theHour int not null,
theCount int not null
-- add indexes of use
-- add foreign key (FK) constraint(s), such as to metric
);
That's it. Two tables. Not each line with a new table each day.
Related
My website is called "Informational System of Hostelry Rooms".
I apply one database creating 6 tables. The first three represents properties of hostelry room: "storeys", "places", "type". The first one represents the storey. The second one the quantity of places per one number. The third one characterizes other characteristics. Every row of every first three tables has own price.
$CR1="CREATE TABLE IF NOT EXISTS storeys(id INTEGER PRIMARY KEY AUTO_INCREMENT, characteristic VARCHAR(30) UNIQUE, price FLOAT(10))";
$CR2="CREATE TABLE IF NOT EXISTS places(id INTEGER PRIMARY KEY AUTO_INCREMENT, characteristic VARCHAR(30) UNIQUE, price FLOAT(10))";
$CR3="CREATE TABLE IF NOT EXISTS type(id INTEGER PRIMARY KEY AUTO_INCREMENT, characteristic VARCHAR(30) UNIQUE, price FLOAT(10))";
When the user decides to make an order, the program makes a sum of three prices by three parameters of the room to get the price of living in the room for 1 day.
I've cared about the data of clients:
$CR4="CREATE TABLE IF NOT EXISTS client(id INTEGER PRIMARY KEY AUTO_INCREMENT, pib VARCHAR(30) UNIQUE, phone VARCHAR(30))";
After the calculation of the price of living in the particular room, it would be better to get the date interval of room usage. Also I have comprehended the absence of opportunity of displaying the order table would not be a norm. So here's the list of fields I should display:
the client name
the storey number
the quantity of places
the other specific
the price
the date of settling
the date of eviction
id of the row in order database table (invisible)
I suppose it wouldn't be problematically, but here's other tables I have:
$CR5="CREATE TABLE IF NOT EXISTS room(id INTEGER PRIMARY KEY AUTO_INCREMENT, id_storeys INTEGER, id_places INTEGER, id_type INTEGER)";
$CR6="CREATE TABLE IF NOT EXISTS order1(id INTEGER PRIMARY KEY AUTO_INCREMENT, id_client INTEGER, id_room INTEGER, price FLOAT(10), start_time DATETIME, finish_time DATETIME);";
So I should display specific columns and here's my attempt:
SELECT order1.id, order1.price, order1.start_time, order1.finish_time, client.pib, storeys.characteristic AS ch1, places.characteristic AS ch2, type.characteristic AS ch3
FROM order1, client, storeys, places, type;
There's no error. But the amount of rows in HTML table is too high. The table had to display one row only because there are one row in order1 and one row in room exclusively. Instead of that it shows 4 rows probably because of the quantity of rows in the tables client, storeys, places and type is sometimes more than 1.
I have no idea how to write down the query. But there are two requirements:
The number of rows in HTML table should equal to the amount of rows in order1 and in room.
The table must contain only the data that is present in room and order1.
And in addition, I have not used any relationships in database yet. Any ideas?
I have a event in which I am storing a string in a variable. Now I want to use that variable to create a new table. Everytime my event runs it creates table with the name of "mon". What is I am doing wrong ?
BEGIN
DECLARE onlyweek INT;
DECLARE mon VARCHAR(20);
SET #mon = "rehan";
CREATE TABLE mon(
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
capacity INT NOT NULL
);
END
Because you use mon instead of #mon. And even then it wont work because you need dynamic SQL for that.
But what is even more important:
Don't do that!
Don't create a table on the fly. Table designs should be static. That smells like a big design flaw.
This is a design mistake. For example, you need to make report for the year. In your design you have to join 12 tables and where-s how to join. And this is very slow.
Better design is creating 2 tables - "months" and "reporting_periods" with foreign key to table 'months'. This way when you need year report - you join only 2 tables by ID with "where".
Table 'months' can be filled once a year using same mysql events.
Then use mysql "stored procedure" (and mysql event) for periodic insert into reporting_period with month id. Months` names can include year as "bad way" or have the field 'year' = 'better one'.
CREATE TABLE months(
id int auto_increment,
name varchar(10),
number int not null,
year int not null,
constraint monthes_pk
primary key (id)
);
and reporting_period
CREATE TABLE reporting_period(
id INT auto_increment,
period_id INT NOT NOT,
capacity INT NOT NULL,
constraint `reporting_period_pk`
primary key (id),
constraint `reporting_period__fk`
foreign key (period_id) references months (id)
);
More about DB design: normalization
I'm trying to keep a record of the earnings of the users of my website and I'm stuck at which of the following designs is best regarding performance and overall usability:
• First way:
In this way a single database will be created containing a table for each year. Each table will have 13 columns, the user ID and the 12 months. The value for each field will be a stringified array with the values of all the days of the month, like so: [12.5, 28.3, 9.75, ...].
Code:
-- Create a database to keep record of the earnings of all users.
CREATE DATABASE IF NOT EXISTS `Earnings_Record`;
-- Create a table for each year containing 13 columns, the user ID and the 12 months.
CREATE TABLE IF NOT EXISTS `Earnings_Record`.`Earnings_2017` (
`ID` INT(11) NOT NULL,
`January` VARCHAR(250) NOT NULL,
`February` VARCHAR(250) NOT NULL,
...
`December` VARCHAR(250) NOT NULL,
PRIMARY KEY (`ID`)
) ENGINE = InnoDB CHARACTER SET utf8 COLLATE utf8_general_ci;
• Second way:
In this way multiple databases will be created, one for each year, containing a table for each month. Each table will have 28-31 + 1 columns, the user ID and the 28-31 days. The value for each field will be a decimal, like so: 12.5.
Code:
-- Create a database to keep record of the earnings of all users for 2017.
CREATE DATABASE IF NOT EXISTS `Earnings_2017`;
-- Create a table for each month with 28-31 + 1 columns, the user ID and the 28-31 days.
CREATE TABLE IF NOT EXISTS `Earnings_2017`.`January` (
`ID` INT(11) NOT NULL,
`Day 1` DECIMAL(10, 2) NOT NULL,
`Day 2` DECIMAL(10, 2) NOT NULL,
...
`Day 31` DECIMAL(10, 2) NOT NULL,
PRIMARY KEY (`ID`)
) ENGINE = InnoDB CHARACTER SET utf8 COLLATE utf8_general_ci;
Since the website will hopefully be running for 5-10 years, which is the best way to design this when it comes to overall performance and long-term maintainability?
(One thing to keep in mind is that the earnings of each user will be updated multiple times every day for active users)
Third way:
Create a single database. Create a single table for each entity:
CREATE DATABASE IF NOT EXISTS Earnings_Record;
CREATE TABLE IF NOT EXISTS Earnings_Record.Users (
UsersId INT AUTO_INCREMENT PRIMARY KEY,
. . .
);
CREATE TABLE IF NOT EXISTS Earnings_Record.Earnings (
EarningsID INT AUTO_INCREMENT PRIMARY KEY,
UserId INT NOT NULL,
EarningsDate DATE,
Amount DECIMAL(10, 2) -- or whatever
CONSTRAINT fk_Earnings_UserId FOREIGN KEY (UserId) REFERENCES Users(UserId)
) ;
Simple. Easy-to-query. Just what you need. This is the SQL way to represent data.
It's hard to answer this - but any solution that requires multiple databases or tables is probably not maintainable, or scalable, or fast.
I really don't understand your business domain - you say you want to maintain earnings per user, but your tables don't have any reference to a user.
To design the database, it would really help to understand typical queries - do you want to find out total earnings for a period? Do you want to find days with high and/or low earnings? Do you want to aggregate earnings over a group of dates, e.g. "every monday"?
I'd start with:
table earnings
-------------
earnings_date (date) (pk)
earnings_amount (decimal 10,2)
Multiple databases -- NO
Splaying the months across 12 columns -- NO
Stringifying -- Only if you never need MySQL to filter on the data or do arithmetic on the data.
All of these are discussed in various ways in this forum.
There is no problem having thousands, even millions, of rows in a table. The other approaches are headache-causers.
I am working on a game where users can buy virtual items with virtual currency, and also give those items away to other users. We need to be able to track the history of the item (who bought it, who it was gifted to, etc) and the current owner. I'm struggling with some of the table design.
My thinking is to have this (with table design simplified slightly and constraints/keys/etc omitted for space):
TABLE order
id INT NOT NULL AUTO_INCREMENT,
buyer_id INT NOT NULL,
paid INT UNSIGNED NOT NULL,
owned_item_id INT NOT NULL,
------------------------------------------------------
TABLE owned_item
id INT NOT NULL AUTO_INCREMENT,
store_product_id INT NOT NULL,
owner_id INT NOT NULL,
------------------------------------------------------
TABLE gift
id INT NOT NULL,
giver_id INT NOT NULL,
receiver_id INT NOT NULL,
owned_item_id INT NOT NULL,
With the idea being that when an item is purchased, both an order and an owned_item are created for that item. If the item is gifted, then a new entry in the gift table is created and the owner_id field is updated.
This approach makes it very easy to determine who currently owns a given item. However, it has redundant data and leaves room for problems with data integrity. If the 'owner_id' field was set incorrectly, we might end up with records that an item that was purchased by A and gifted to B but is now inexplicably owned by C.
How should such a structure be normalized? I've considered eliminating the owned_item table:
TABLE order
id INT NOT NULL AUTO_INCREMENT,
buyer_id INT NOT NULL,
paid INT UNSIGNED NOT NULL,
product_id INT NOT NULL,
------------------------------------------------------
TABLE gift
id INT NOT NULL,
giver_id INT NOT NULL,
receiver_id INT NOT NULL,
order_id INT NOT NULL,
I don't like this solution because finding all of the items that some person owns becomes a very complex operation (find every gift record X where the recipient is A and no later gift record exists for the same order, combined with find every order record Y where the buyer is A and no gift records exist for that order) but if that's the correct solution then I'll make do.
Something like this would be a good 3nf schema for what you're looking to do.
Entities and transactions are kept generic in order to allow all entity / transaction relationships to be simplified.
-- An Entity is a person or business, as a party in a transaction
CREATE TABLE entity (
id INT NOT NULL AUTO_INCREMENT,
entity_type ENUM('store', 'person') NOT NULL
name VARCHAR NOT NULL
);
-- Unique item types - items are each an instance of an item-type
-- e.g. the item "Steve's broom" may be an item of type "broom"
CREATE TABLE item_type (
id INT NOT NULL AUTO_INCREMENT,
name VARCHAR NOT NULL
);
-- Non-unique item, instance of an item-type owned by an entity
CREATE TABLE item (
id INT NOT NULL AUTO_INCREMENT,
-- optionally include owner_id as a quick-reference to the current owner of the item
owner_id INT NULL REFERENCES entity (id),
-- FK to unique item types, e.g. "broom"
item_type_id INT NOT NULL REFERENCES item_type (id),
-- possible description, e.g. "Steve's broom"
description VARCHAR NOT NULL
);
-- A transaction is a sale, gift, or other method of transferrence
-- of an item between entities. Transaction is a bad name, because
-- it's a reserved word. That's why it's encased in ticks.
-- You'd probably be better off choosing a different generic name
CREATE TABLE `transaction` (
id
-- transaction_type can be NULL in cases of origination with entity
transaction_type ENUM('sale', 'gift') NULL,
-- NULL in cases of origination with an entity
from_entity_id INT NULL REFERENCES entity (id),
to_entity_id INT NOT NULL REFERENCES entity (id),
-- amount can be 0 in cases of gifts
amount DECIMAL(9,2) UNSIGNED NOT NULL DEFAULT 0
);
A "gift" transaction would have an amount of 0 (or NULL, if you wanted to make it nullable).
An "origin" transaction (e.g. something was made, or found) would have no transaction_type, and 0 amount.
To know who the current owner of an item is, use a view that retrieves the last "to_entity_id" for that item in the transaction table, e.g.:
SELECT
e.name
FROM entity AS e
INNER JOIN `transaction` AS t ON e.id = t.to_entity_id
INNER JOIN
(SELECT MAX(id) AS id
FROM `transaction`
WHERE item_id = 5) AS tx ON tx.id = t.id
Alternatively, you could also store the owner_id in the item table (see note above in the schema). This would be a little redundant, and would require updating that table on each transaction, but would save a lot of expensive queries to know who owns what.
I'm working on an application which tracks prices for certain items.
Each price has a reference to an item, a business that sells that item, and the location the item is being sold at. Now, normally, this would do just fine:
CREATE TABLE `price` (
`priceId` INT UNSIGNED NOT NULL AUTO_INCREMENT, -- PK
`businessId` INT UNSIGNED NOT NULL,
`itemId` INT UNSIGNED NOT NULL,
`locationId` INT UNSIGNED NOT NULL,
`figure` DECIMAL(19,2) UNSIGNED NOT NULL,
-- ...
)
But I have the following problem:
The application logic is such that one item at one business at one location can have multiple prices (at this point it's not really important why), and one of those prices can be an official price - an item doesn't have to have an official price, but if it does, there can be only one.
The question is; how to model this to ensure data integrity?
My initial idea was to create an additional table:
CREATE TABLE `official_price` (
`priceId` INT UNSIGNED NOT NULL -- PK + FK (references price.priceId),
-- ...
)
This table would hold priceId:s for prices that are official, and the PK/UNIQUE constraint would take care of the 'one-or-none' constraint.
This seems like a workable solution, but I'm still wondering if there's a better way to handle this situation?
You can use this dirty hack:
add a field is_official to price table, null as a value is possible in it
create an unique composite index priceId + is_official
for the official prices put 1 to is_official
for not official left it to be null
You could make the price table hold only official prices (with the figure possibly null), put a unique constraint on (businessId, itemId, locationId), and add another table of auxiliary prices referencing priceId.