Accurate tables for Database normalization - java

I am thinking on how could I normalize as accurate as possible my tables in my database.
I have to develop a monitoring system where the system should analyse all the outgoing messages(Emails, SMS..) send to customers and their related feedback(status(0,1 or more)).
It means that for 1 outgoing message(With for ex MAILID: 123) I can have multiple different feedbacks(SENT, NOT DELIVERED, DELIVERED, CLICKED, OPENED...) received at different time intervals. For some feedback received I must retrieve the information of what the Email Service provider did in term of "Action". Did they send the email again to the customer?, did they manage to resolve the servers issues if not delivered? etc..
EDIT: I am sorry in fact my MAIL ID columns are all VARCHARS (Java Strings). Long story short, In fact I have to process XML files and unmarshal them to Java Object and persist them into my Mysql dataBase where MAIL ID is in the form of BMM1EP_34022503920_1200180009
To clarify I thought I should have 4 main tables.
Table SentMessages with columns:
MailId VARCHAR primary key(not null)
Form_Name varchar(50)
Language varchar(10)
OutPut_Mode varchar(10)
Table FeedBackMessages with columns:
Id INT AutoIncrement primary key (not null)
MailId VARCHAR
Return_Date DATE
Return_Time DATETIME
FOREIGN KEY (MailId) REFERENCES SentMessages (MailId)
Table Status with columns:
Id Int AutoIncrement primary key (not null)
MailId VARCHAR
Status VARCHAR(50)
FOREIGN KEY (MailId) REFERENCES SentMessages(MailId)
Table Action with columns:
Id Int AutoIncrement primary key(not null)
ActionTaken VARCHAR(100)
MailId VARCHAR
FOREIGN KEY (MailId) REFERNCES Status(Id)
Is my design bad? Help will be highly appreciated as I really struggle it is my first time designing a real database for a concrete project. Thanks to all of you!

It helps if you use a semi-formal natural language to define your business domain. As I understand it:
There are 0..n email messages
Each email message will have 0..n feedback items
Each feedback item has 1 status, and may have additional action information.
If that's accurate, the design would be something like:
Table SentMessages with columns:
MailId varchar primary key(not null)
Form_Name varchar(50)
Language varchar(10)
OutPut_Mode varchar(10)
Table FeedBackMessages with columns:
Id INT AutoIncrement primary key (not null)
MailId varchar
Return_Date DATE
Return_Time DATETIME
Status VARCHAR(50)
ActionTaken VARCHAR(100)
FOREIGN KEY (MailId) REFERENCES SentMessages (MailId)

Related

How to get n:m tables?

I have a spring-boot application with a MySql database. I have a many-to-many relationship between a pizza table and a topping table so I've made an extra table where I store these relationships. The tables:
CREATE TABLE topping (
id SERIAL PRIMARY KEY,
topping_name VARCHAR(64) NOT NULL,
price INT NOT NULL,
spicy bool NOT NULL
);
CREATE TABLE pizza (
id SERIAL PRIMARY KEY,
pizza_name VARCHAR(64) NOT NULL
);
CREATE TABLE pizza_with_topping (
pizza_id BIGINT UNSIGNED NOT NULL,
topping_id BIGINT UNSIGNED NOT NULL,
CONSTRAINT pizza_with_topping_ibfk_1
FOREIGN KEY(pizza_id)
REFERENCES pizza(id),
CONSTRAINT pizza_with_topping_ibfk_2
FOREIGN KEY(topping_id)
REFERENCES topping(id)
);
In spring-boot I found that I have to extend the CrudRepository interface and I can call the findAll() method from this to get the contents of a table. At the momment I get the contents of all 3 tables like so:
Iterable<Pizza> pizzasInDb = pizzaRepository.findAll();
Iterable<Topping> toppingsInDb = toppingRepository.findAll();
Iterable<PizzaWithTopping> pizzaToppingConnectionTable = pizzaWithToppingRepository.findAll();
After this based on these 3 tables I manually create objects that contain both the pizza's name and it's toppings. Since I have set foreign keys in pizza_with_topping table I was wondering if there is a better way to get this model? Maybe with the call of built-in functions that automatically makes this model object for me based on the foreign keys.
Yes, there is. You can model your domain with many-to-many relationships using JPA. If you are using annotation this cam be achieve using #ManyToMany
There is an example here

Flyway and PostgreSQL nullable definition of foreign key still generates a non-null constraint

I use Spring Boot and Flyway with this initialization script:
CREATE TABLE ADDRESS(
ID bigserial NOT NULL PRIMARY KEY
);
CREATE TABLE ROLE(
ID bigserial NOT NULL PRIMARY KEY
);
CREATE TABLE PERSON(
ID bigserial NOT NULL PRIMARY KEY,
FIRST_NAME VARCHAR(255),
LAST_NAME VARCHAR(255),
ADDRESS bigserial NOT NULL REFERENCES ADDRESS (ID),
ROLE bigserial REFERENCES ROLE (ID) -- notice here is no 'not null'
);
All the relationship between the tables is that:
Each PERSON has 0-1 ROLE. So, each ROLE belongs to 0-n PERSON. Hence, this relationship is nullable.
Each PERSON has 1 ADDRESS. So, each ADDRESS belongs to 1-n PERSON. Hence, this relationship is not-null.
As soon as I start the application (I have also tried to post the query straight to the PostgreSQL database schema), there is somehow generated constraint not-null between the PERSON and ROLE tables.
Using DataGrip, I select SQL Scripts -> Generate DDL to Query Console and get the DDL for the tables (see below, new lines and roles definitions omitted for sake of brevity).
To my surprise, the NOT NULL is there although I haven't defined such constraint. How to get rid of it aside from altering table?
create table if not exists address
(
id bigserial not null
constraint address_pkey primary key
);
create table if not exists role
(
id bigserial not nullconstraint role_pkey primary key
);
create table if not exists person
(
id bigserial not null
constraint person_pkey primary key,
first_name varchar(255),
last_name varchar(255),
address bigserial not null
constraint person_address_fkey references address,
role bigserial not null -- why is 'not null' here?
constraint person_role_fkey references role
);
The version of PostgreSQL I use (through SELECT version()) is:
PostgreSQL 10.13, compiled by Visual C++ build 1800, 64-bit
"8.1.4. Serial Types":
The data types smallserial, serial and bigserial are not true
types, but merely a notational convenience for creating unique
identifier columns (similar to the AUTO_INCREMENT property supported
by some other databases). In the current implementation, specifying:
CREATE TABLE tablename (
colname SERIAL
);
is equivalent to specifying:
CREATE SEQUENCE tablename_colname_seq AS integer;
CREATE TABLE tablename (
colname integer NOT NULL DEFAULT nextval('tablename_colname_seq')
);
ALTER SEQUENCE tablename_colname_seq OWNED BY tablename.colname;
Note the NOT NULL.
Don't use bigserial for the foreign key. That doesn't make much sense. Simply use bigint.
CREATE TABLE IF NOT EXISTS person
(...
role bigint REFERENCES role);
Possible solution 1:
Changing Biserial to Bigint does not remove the null constraint set to foreign key column when running flyway in springboot to write into postgres DB (at least for my case)
postgres:11.3-alphine 3.4
flyway: 8.0.5
To be secure, need to add scripts to alter columns to be nullable
ALTER TABLE mytable ALTER COLUMN mycolumn DROP NOT NULL;
Change Postgres column to nullable
Possible solition 2:
When Spring boot set JPA Hibernate ddl configuration to create, create-drop, update, flyway DB migration script will be updated by JPA entities properties. NOT NULL constraints can be added by JPA entities.
Change JPA Hibernate ddl configuration to none or validate will ensure only flyway script is used to create schema.
JPA Hibernate ddl configuration

create a tree structure in java using hierarchical data from database

I have this problem at hand which is as follows :
There is a many-to-many relationship between User & Group.The back-end has tables for the respective entity classes as well as an intersection table User_Groups which stores information about the association of a user to groups.The Groups table has two columns which are relevant to the problem at hand.The Structure of group table is as follows:
Table name - GROUP
CREATE TABLE IF NOT EXISTS
GROUP
(
GROUP_ID INT NOT NULL AUTO_INCREMENT ,
NAME VARCHAR(50) NULL ,
DESCRIPTION VARCHAR(50) NULL ,
CREATED_DATE DATE NULL ,
CREATED_BY VARCHAR(50) NULL ,
MODIFIED_DATE DATE NULL ,
MODIFIED_BY VARCHAR(50) NULL ,
GROUP_TYPE_ID INT NULL ,
PARENT_GROUP_ID INT NULL ,
PRIMARY KEY (GROUP_ID) ,
INDEX fk_groupTypeId_idx (GROUP_TYPE_ID ASC) ,
CONSTRAINT fk_groupTypeId FOREIGN KEY (GROUP_TYPE_ID )
REFERENCES efc_group_type (GROUP_TYPE_ID )
ON DELETE NO ACTION
ON UPDATE NO ACTION);
------------------------------------------------------------------------------------------
Table name - USER_GROUPS
CREATE TABLE IF NOT EXISTS
EFC_USER_GROUPS
(
USER_ID int(11) NOT NULL,
GROUP_ID int(11) NOT NULL,
CREATED_DATE date DEFAULT NULL,
PRIMARY KEY (USER_ID,GROUP_ID),
KEY FK_USERID_idx (USER_ID),
KEY FK_GROUPID_idx (GROUP_ID),
CONSTRAINT FK_GROUPID_USERGROUPS FOREIGN KEY (GROUP_ID)
REFERENCES efc_group (GROUP_ID),
CONSTRAINT FK_USERID_USERGROUPS FOREIGN KEY (USER_ID)
REFERENCES efc_user (USER_ID));
The parent_group_id is basically acting as a foreign column to the group_id. A group can have sub-groups and hence the need to store the parent_group_Id. For each sub-group added, we store the parent_group_id for that group under which sub-group was added. Now that you have some idea about the data model, I'll illustrate what my problem is:
I am trying to construct a tree like structure for the parent-child relationship between groups & sub-groups for a certain user. So corresponding to a certain user Id, I am able to get the groups that he is part of from the user_groups table.Then I am able to filter the groups into two lists, one representing the parent nodes and the other has all child nodes. Now the hierarchy between groups is stored in the group table. I am not able to figure out how to implement that in java. I already have the list with me but in that list each group can have parents above it and also children below it. I am not able to understand how to build the top to bottom hierarchy. My sole purpose is to build that XML constituting the parent-nodes down to last child node and send it to the front-end.
P.S : I have googled quite a bit.I am running short of ideas :(. Please help me

Mahout and custom table for data model

The documentation says that the table of ratings should look like this:
CREATE TABLE taste_preferences (
user_id BIGINT NOT NULL,
item_id BIGINT NOT NULL,
preference REAL NOT NULL,
PRIMARY KEY (user_id, item_id)
);
However, in my implementation table of ratings is as follows:
CREATE TABLE taste_preferences (
profile_id BIGINT NOT NULL,
event_id BIGINT NOT NULL,
status_id BIGINT NOT NULL,
PRIMARY KEY (user_id, item_id)
);
Where the grade is in the form status_id (go, no go, maybe I'll go).
The users table as follows:
CREATE TABLE user (
profile_id_1 BIGINT NOT NULL,
profile_id_2 BIGINT NOT NULL,
profile_id_3 BIGINT NOT NULL,
...
);
A user can have multiple profiles, I need to compare these data to users.
I need to write its own implementation of data model? Which way do I see, that would solve this problem? Thanks!
You don't have rating data here, in any form. So, you can't use ratings in recommendations. That's fine; you just have "boolean" data.
Or, you're saying you need to use status but I'm not clear how you want to use it.
You can certainly use your taste_preferences table. Just use MySQLBooleanPrefJDBCDataModel or similar. The user table is irrelevant.

Mapping Linking Table with 3 PK's in Hibernate

right now I'm having trouble mapping a linking table with Hibernate.
First of all I want to explain what I want to map:
I have 3 tables: Product , DocumentType, Language.
One Product can have each DocumentType (at the moment we have 7 DocumentTypes) in each specific Language (at the moment we have 3 Languages)
That means product "1" can have DocumentType "A" in language "EN", "ES" and "FR".
I created a linking table with 3 foreign keys which are also composite primary key.
Here is how my sql looks like.
CREATE TABLE Person(
id int PRIMARY KEY AUTO_INCREMENT,
name varchar(255)
);
CREATE TABLE DocumentType(
id int PRIMARY KEY AUTO_INCREMENT,
name varchar(255),
key varchar(255)
);
CREATE TABLE Language(
id int PRIMARY KEY AUTO_INCREMENT,
name varchar(255),
code varchar(2)
);
CREATE TABLE Person_DocumentType_Language(
person_id int NOT NULL,
doc_id int NOT NULL,
lang_id NOT NULL,
FOREIGN KEY(person_id)
REFERENCES Person(id),
FOREIGN KEY(doc_id)
REFERENCES DocumentType(id),
FOREIGN KEY(lang_id)
REFERENCES Language(id),
PRIMARY KEY(person_id, doc_id, lang_id)
);
With the last linking table I could tell which Person has which DocumentTypes and in which Languages.
I'm mostly interested in the information which DocumentType has which Language for one Person.
Say I'm Person A. Now I want to know which DocumentTypes I have with which Languages. In SQL it would look like this I think:
Select doc_id, lang_id from Person_DocumentType_Language where person_id=1
Does that make sense? And how could I map this in Hibernate?
One approach is have a Map from DocumentType to Language. I'm a bit rusty on the exact annotation, but here is a start:
public class Person {
#Id
public int id;
#OneToMany(targetEntity=Language.class)
#MapKeyClass(Integer.class)
#CollectionTable(name="Person_DocumentType_Language")
#MapKeyColumn(name="doc_id")
public Map<DocumentType,Language> docTypeLang;
}

Categories

Resources