How to select few columns from different database tables considering some conditions? - mysql

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?

Related

How to design a table, where the values of one column may come from either of two other tables in a database?

I am trying to implement the following in a SQL database:
I have three tables.
CREATE TABLE company1(
id int NOT NULL,
prod_id int NOT NULL,
company1_quality_value int)
CREATE TABLE company2(
id int NOT NULL,
prod_id int NOT NULL,
company2_quality_value int)
CREATE TABLE production(
id int NOT NULL,
prod_id int NOT NULL,
corrected_quality_value int)
Suppose two companies calculate some quality value for a product and I store this in two separate tables. Now also suppose that I want to make a production table for this product, with a column corrected_quality_value. Since I trust company2 more than company1, I would like this column to be company2_quality_value whenever company2 has the value stored for the specific product ID prod_id. However, this value may be NULL. Only in this case I will take the value company1_quality_value, which we can suppose will always exist.
My question is: should I try and design the relationship between these values from the get go (and if so, how would I do it best) or should I just do it in the backend and leave the values without a relationship.
The second option just seems odd, since in my mind this would create at least some data duplication (since the values in corrected_quality_value are already stored somewhere else).

What is the best solution to set keys in this SQL table representing room rates of an accomodation service?

I am not so into database and I have the following doubt:
I have this room_rate table that represent the rate reserverations of an accomodation system:
id bigint(20) unsigned NO PRI NULL auto_increment
rate_name varchar(255) NO NULL
rate double NO NULL
date_from datetime NO PRI NULL
date_to datetime NO PRI NULL
id_room_tipology_fk bigint(20) unsigned NO PRI NULL
time_stamp datetime YES NULL
I have that the primary key is composed by the following field:
1) id: an auto increment id.
2) date_from: the starting date.
3) date_to: the edning date.
4) id_room_tipology_fk: the room tipology link to another table.
A record of this table simply represent how much is the cost of a room beloning to a tipology of rooms (represented by id_room_tipology_fk) in a specific range of time represented by the date_from and date_to dates.
I want to avoid that a same room tipology have 2 records in the table in the same range of time.
I am asking if using the previous primary key subset is good or if I have to exclude the id field.
Basically I can't have something like this:
1 rate1 50 01/01/2017 10/01/2017 5 04/12/2016
2 rate2 70 01/01/2017 10/01/2017 5 06/12/2016
Because I can't have 2 rate for the same room tipology (5) in the same period.
What is the best solution to correctly model this situation?
Based on the explanation in the comments, you can just use a unique index/constraint. A simple way is to build a unique index:
create unique index unq_roomrate_room_datefrom
on room_rate(id_room_tipology_fk, date_from);
This only uses the start date, but you can include the end date as well.
You can put the same check into the table definition, if you prefer:
constraint unq unq_roomrate_room_datefrom unique (id_room_tipology_fk, date_from);
Assuming that the table doesn't ever have the same id_room_tipology_fk with overlapping date_from-date_to ranges:
Although (id, date_from, date_to, id_room_tipology_fk) might be unique not null, it's not a primary key. Because (id), (date_from, id_room_tipology_fk) and (date_to, id_room_tipology_fk) all uniquely identify a row while no subset of any of them does, so they would all be candidate keys (declared unique not null), one of which you could choose to declare as primary key instead.
Each interval-id_room_tipology_fk pair is unique, so it can only appear with the one rate that is in the one row it appears in. So you don't need to add a constraint.
But if there's no guarantee for non-overlap then you need to enforce it with a constraint you have declare in a trigger. See the question & answers at Find date range overlaps within the same table, for specific user MySQL.

Database table design task

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.

Database schema for storing ints

I'm really new to databases so please bear with me.
I have a website where people can go to request tickets to an upcoming concert. Users can request tickets for either New York or Dallas. Similarly, for each of those locales, they can request either a VIP ticket or a regular ticket.
I need a database to keep track of how many people have requested each type of ticket (VIP and NY or VIP and Dallas or Regular and NY or Regular and Dallas). This way, I won't run out of tickets.
What schema should I use for this database? Should I have one row and then 4 columns (VIP&NY, VIP&Dallas, Regular&NY and Regular&Dallas)? The problem with this is it doesn't seem very flexible, thus I'm not sure if it's good design.
You should have one column containing a quantity, a column that specifies the type (VIP), and another that specifies the city.
To make it flexible you would do:
Table:
location
Columns:
location_id integer
description varchar
Table
type
Columns:
type_id integer
description varchar
table
purchases
columns:
purchase_id integer
type_id integer
location_id integer
This way you can add more cities, more types and you allways insert them in purchases.
When you want to know how many you sold you count them
What you want to do is have one table with cities and one table with ticket types.
Then you create a weak association with [city, ticket type, number of tickets].
That table will have 2 foreign keys, therefore "weak".
But this enables you to add or remove cities etc. And you can add a table for concerts as well and your weak table you will have another foreign key "concert".
I think this is the most correct way to do it.
CREATE TABLE `tickets` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`locale` varchar(45) NOT NULL,
`ticket_type` varchar(45) NOT NULL
}
This is a simple representation of your table. Ideally you would have separate tables for locale and type. And your table would look like this:
CREATE TABLE `tickets` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`locale_id` int(11) NOT NULL,
`ticket_type_id` int(11) NOT NULL
}

MySQL rating database structure

I'm trying to create a database that stores the students grade for each homework assignment I want to be able to store the grade and how many times that student got a certin grade for example a student got an A+ 30 times, for each student, as well as how many grades a student got. And how much a grade is worth in points for example an A is worth 4.3.
So I was wondering what is the best way to build my MySQL database what do I need to add and what do I need to drop and how can I store numbers like 4.3 for example.
My database so far
CREATE TABLE grades (
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
grade INT UNSIGNED NOT NULL,
student_work_id INT UNSIGNED NOT NULL,
student_id INT UNSIGNED NOT NULL,
date_created DATETIME NOT NULL,
PRIMARY KEY (id)
);
CREATE TABLE work (
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
student_id INT UNSIGNED NOT NULL,
title TEXT NOT NULL,
content LONGTEXT NOT NULL,
PRIMARY KEY (id)
);
CREATE TABLE IF NOT EXISTS student (
id int(8) NOT NULL auto_increment,
student varchar(20) NOT NULL,
PRIMARY KEY (`id`)
)
example of output.
student | grade | count
1 A 10
1 C 2
1 F 4
2 B 20
2 B- 3
2 C+ 10
student | grade | points
1 A 4.3
2 B+ 3.3
3 B- 2.7
4 D+ 1.3
student | total grades
1 90
2 80
3 100
4 1
I think a student - grade - assignment schema would be ok. You should count the number of grades of a student with a query and not maintain that information in your database.
At a conceptual level (not strict mysql), I would do something like this.
table student (
id int (primary key)
varchar name
... // other student attributes (e.g. phone number)
)
table grade (
id int (primary key)
name varchar // e.g. "A+", "B-", etc.
float points // grade value in points
)
table assignment (
id int (primary key)
name varchar // assignment name
student_id int (foreign key) // student that completed the particular assignment
grade_id int (foreign key) // grade achieved in particular assignment
... // other assignment attributes (e.g. due date)
)
Many would suggest that you have a student table, a grade table and a table that relates the student and grade table. You could then do counts based on the table that relates the two with a procedure. Many believe that having a grade and a student in the same table is poor relational design.
Unless you want to use a view, which is really not necessary in this case, you wouldn't store the amount of times a student got a certain grade; rather, you would make a query that gave you that information for each student when you needed it. One example using your current schema, to tell you how many times a particular student having id st_id got each grade, would be like
SELECT COUNT(1) FROM grades WHERE student_id = st_id GROUP BY grade
This will look at all the rows where student st_id got each grade and count them up separately.
As far as storing a mapping from letter grade to the amount of points that its worth, you could do one of two things - either have a table mapping from letter grade to point amount, or just store the point amounts directly. Personally, I think the former is a little bit cleaner as it allows you to change point amounts if the scale changes (not that that should happen often).
Other than that, I think you're doing pretty good. The only thing I would say is that if there is always a one-to-one mapping between grade and work, I might make grade part of the work table rather than separate them. That is, only if there isn't information in the grade table that doesn't belong in the work table.
Looking at your tables it appears that there's some normalizing that you can do, or I might be misunderstanding the objective. I would assume that students and work items are only connected by a grade, which would make your grades essentially a cross-reference table. As a result, you wouldn't reference the student_id column within the work table. Off the cuff, I would change it such that the tables look more like this:
CREATE TABLE student (
student_id int(8) NOT NULL auto_increment,
student varchar(20) NOT NULL,
PRIMARY KEY (student_id)
);
CREATE TABLE work (
work_id INT UNSIGNED NOT NULL AUTO_INCREMENT,
title TEXT NOT NULL,
content LONGTEXT NOT NULL,
PRIMARY KEY (work_id)
);
CREATE TABLE grades (
grade_id INT UNSIGNED NOT NULL AUTO_INCREMENT,
grade decimal(4,2) UNSIGNED NOT NULL,
work_id INT UNSIGNED NOT NULL,
student_id INT UNSIGNED NOT NULL,
date_created DATETIME NOT NULL,
PRIMARY KEY (id)
);
Note that I changed the grade column to a decimal (I'm a SQL Server guy, so MySQL might be different), but any type that can handle non-integer numbers works. With that design, you can then pull your queries as needed to get the types of output you need.
Josh
assuming -
there's more than one student
there's more than one assignment / piece of work to be graded against
more than one student can complete a specific set work/assignment
only one grade can be earned per assignment
I'd go with -
a table for the definition of each set piece of work / a specific assignment.
a table to define each student
a third table to record the result of each assignment per student, ie to store the grade per assignment.
eg -
CREATE TABLE work (
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
student_id INT UNSIGNED NOT NULL,
assignment_id int unsigned not null,
grade DECIMAL(1,1)
gradedesc VARCHAR(1)
PRIMARY KEY (id)
);
CREATE TABLE IF NOT EXISTS student (
id int(8) NOT NULL auto_increment,
student varchar(20) NOT NULL
PRIMARY KEY (`id`)
)
Create table assignment (
id int(8) not null auto_increment,
title TEXT NOT NULL,
content LONGTEXT NOT NULL
primary key(id)
Then, create some views to display the output in the format you want, eg -
Create view graded_students as
(select s.student,
w.gradedesc as grade,
w.grade as points,
w.title
from work w,
student s
where w.student_id = s.id
and w.grade is not null )
Create view aggregate_grades as
(select s.student,
sum(w.grade) as "total grades",
from work w,
student s
where w.student_id = s.id
and w.grade is not null
group by s.student)
create view grades_by_assignment as
(select s.student,
a.title,
w.gradedesc as grade
from student s,
work w,
assignment a
where a.id = w.assignment_id
and s.id = w.student_id )
I'm more of an oracle and sql server person, so this may not be 100% mysql compliant (and I haven't tested it) but something like that would do the trick I think.
If you want to normalize the data even further you could break out the grade description/value to another table too, or just display the grade description in your application based on the stored value (eg grade value 4.5 always displays as "A", etc)