I am having an issue that involves a differentiation between whether a status update belongs to a user or a company. Let me explain: Individuals can post statuses as a user or as a company. A user can be a member/owner of a company and switch to a company in the dashboard much like Facebook. The problem is: how will we set in the database whether a status was posted by a company or by a user?
My solution was to have a company column that was a Boolean variable and when we query for each status to display we check if it was from a company. If so then we grab the company_id and look up the name and other relevant information in the database and display it on the site. Does this sound like the right approach? Additionally, does the schema below look correct?
**Company**
id int(11)
name varchar (255)
**Company_members**
company_id int(11) FK_Company
user_id int(11) FK_Users
owner BOOLEAN
**Users**
id int(11)
name varchar (255)
**Status**
id
date DATETIME
user_id FK_Users
company_id FK_Company
company BOOLEAN
Your schema looks good, but the company boolean in the Status table seems redundant. You can just set the company_id to NULL when the status is for an individual's account, and then query SELECT * from Status WHERE company_id IS NULL to get individuals' statuses, and SELECT * FROM Status WHERE company_id IS NOT NULL to get companies' statuses.
Use the Party Model. You need to use table inheritance. Single Table inheritance is simpler and faster but may use nulls.
create table party_type (
id int primary key,
description text not null unique
);
insert into party_type values
(1, 'Individual'),
(2, 'Organization');
create table party (
id serial primary key,
type int not null references party_type(id),
name text not null
);
create table status_update(
id serial primary key,
date datetime,
party_id not null references party(id)
);
(syntax is postgres but you should be able to translate to mysql easily)
Related
Let's say I have tables:
create table people (
human_id bigint auto_increment primary key,
birthday datetime );
create table students (
id bigint auto_increment primary key,
human_id bigint unique key not null,
group_id bigint not null );
create table teachers (
id bigint auto_increment primary key,
human_id bigint unique key not null,
academic_degree varchar(20) );
create table library_access (
access_id bigint auto_increment primary key,
human_id bigint not null,
accessed_on datetime );
Now I want to display information about a library access, along with the information whether it was a student or a teacher (and then the id corresponding to the table) (let's say I want something like SELECT access_id,id,true_if_student_false_if_teacher FROM library_access), in an idiomatic way.
How do I form the query (in case such database was already deployed) and what are better and more idiomatic ways to solve that problem (in case it wasn't deployed so far).
MariaDB 5.5, database accessed by Go and nothing else.
Thanks in advance.
You said you need to know which table the data comes from. You can use union all for this:
select la.access_id, s.id, 'Students' as source_table
from library_access la
join students s on la.human_id = s.human_id
union all
select la.access_id, t.id, 'Teachers' as source_table
from library_access la
join teachers t on la.human_id = t.human_id
Without looking at your tables or any idea as to what you want returned in the select statement:
SELECT *
FROM people a,
students b,
teachers c,
library_access d
WHERE a.human_id = b.human_id
AND a.human_id = c.human_id
AND a.human_id = d.human_id
So first up I'm not sure if this is a double post or not because I don't know how the exact approach or feature is called and if it even exist.
I know that MySQL has a feature called joins
My plan is to link two MySQL tables in relation 1:n one is t_user the other one t_event.
t_user:
CREATE TABLE t_user (
uId INT(6) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(25) NOT NULL,
...
)
t_event:
CREATE TABLE t_event (
eId INT(6) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(40) NOT NULL,
date DATETIME NOT NULL,
members ???,
...
)
I want the users to "subscribe" to the events and get stored in the members column as a list (?). This would be no problem if only one user would subscribe to one event. But I have no idea how to setup the t_event table to store more than one user and how to query for all the events a user has "subscribed" for.
This is usually done via third table:
CREATE TABLE t_eventsusers (
eId INT(6),
uId INT(6)
)
I am confused about the correct/most efficient way to place data in my dababase table when there is a OneToOne relationship.
For example, I have a users table.
I now wish for each user to be able to state his current country location.
i then want to be able to search the datatable for users by current location.
The way that I have done this is to create 3 separate tables. i.e
table one - users : just contains the user information:
CREATE TABLE users(
id MEDIUMINT UNSIGNED NOT NULL AUTO_INCREMENT,
firstName VARCHAR(30) NOT NULL,
lastName VARCHAR(40) NOT NULL,
);
Table two country list: a list of countries and respective Ids for each country
PHP Code:
CREATE TABLE countrylist(
country_id MEDIUMINT UNSIGNED NOT NULL,
country VARCHAR(60) NOT NULL,
INDEX country_id ( country_id, country ),
INDEX countrylist (country, country_id ),
UNIQUE KEY (country)
);
Table 3; contains the userId and the countryId he lives in:
PHP Code:
CREATE TABLE user_countrylocation(
country_id VARCHAR(60) NOT NULL,
id MEDIUMINT UNSIGNED NOT NULL,
INDEX country_id (country_id, id ),
INDEX user_id (id, country_id )
);
Alternatively, should I place the countryId in the users table and completely get rid of the user_countrylocation. i.e in each user column, I will place a country_id for the country he lives in.
The problem is that I have over 20 similar tables as above that give details on users; i.e languages spoken, age-group, nationality etc.
My concerns is that if I place this unique information in each users column in the user table, then what would be the most efficient way to search the database: that is why I opted for the style above.
So, I really request for some advice on the most efficient/correct way to plan the database.
If you are going to have a huge data then you should keep the same approach and use the following method to keep the one to one constraint satisfied
if you don't have a huge data then you should keep the look up tables like country and use the reference for user in a column. but then you may need to allow them nulls that is make such optional information columns nullable.
The most efficient and exactly correct way is to first delete the data from the third table "user_countrylocation" for the user to be updated. Then insert the new location for the user. don't forget to use transaction.
your table 3 should have
country_id MEDIUMINT UNSIGNED NOT NULL,
instead of
country_id VARCHAR(60) NOT NULL,
and also change tyhe column name from id to user_id in all tables.
if you are using a stored procedure it would be like
create procedure sp_UpdateUserCurrentCountry (
#userID MEDIUMINT UNSIGNED,
#CountryID MEDIUMINT UNSIGNED)
begin
as
delete from user_countrylocation
where user_id = #userID
insert into user_countrylocation
(
country_id,
user_id
)
values
(
#CountryID,
#userID
)
END
One to One relations are usually mapped via Foreign Keys linking the two tables together. A third mapping table is only required for Many to Many relationships. So, you should ideally have a Foreign Key Country_ID in your Users table.
Your SELECT query would then look like
SELECT * FROM Users
WHERE Country_ID = (
SELECT Country_ID FROM Countries
WHERE Country_Name = 'USA'
);
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
}
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)