Activerecord linking 2 tables - activerecord

I have been able to make 2 ActiveRecord tables, Profile and Bot. I have been unable to figure out how to link them properly.
There are thousands of Profiles with columns username, gender. A handful of Bots with columns botname, level
When a bot visits a profile two pieces of info need to be recorded. visited and response should be updated for that specific bot. visited is a boolean that will indicate that one particular bot has visited that one particular profile. the response is a string, again like the visited this is a response for one particular bot that was sent by one particular profile. I am thinking I need a 3rd table that joins these two tables.
I need to keep a record of every profile that every bot visits and the response that happens when it visits.
How can I create this relationship and how can I set/update the columns?
Thanks

I'm not completely certain of your requirements, so I will restate them:
Table Profile: id, username, gender (note that I changed the table names to singular)
Table Bot: id, botname, level
The "bots" somehow "visit" profiles. You need to track when a bot has visited a profile.
When a bot visits a profile, a "response" string is generated and that response string needs to be preserved. I'm assuming it needs to be preserved with the record of the visit.
I think your instincts about a join table are good. I don't think a boolean "visited" column works, however, because if you have a record of a visit, that's an indication that the profile was visited. If the record doesn't exist, then it wasn't visited.
Given this, I think your tables look like this:
profile
---------
profile_id integer autoincrement
username varchar(255)
gender ...
bot
---------
bot_id integer autoincrement
name varchar(255)
level ...
visit
---------
visit_id integer autoincrement
bot_id integer
profile_id integer
visit_time datetime
response varchar(255)
To maintain the integrity of your data, you'll want to set up foreign key constraints between this visit table and your profile and bot tables.
alter table visit
add constraint visit_profile_profile_id_fk
foreign key (profile_id)
references profile (profile_id);
alter table visit
add constraint visit_bot_bot_id_fk
foreign key (bot_id)
references profile (bot_id);
You'll need to decide if it's "legal" for a given bot to visit a particular profile more than once. If it's not, you should put a unique constraint on the combination of profile_id and bot_id in the visit table, and catch the duplicate key errors when your DBMS throws them at you (or otherwise handle dupes.)
I hope that helps.

Related

Correct way to model foreign keys to entities that do not (yet) exist?

I'm building a Spring Boot application using Spring Data JPA. I'll give a simplified description of the application that illustrates my problem:
I have a table of Students that has a student_id primary key and various personal information (incl name, etc). This personal data is loaded from an external source and may only be retrieved once the student gives his permission to retrieve it by logging into the application. I thus cannot create a list of all the users that might log in ahead of time. They are created and inserted into the database when the student logs in the first time.
I also load data sets like historical grades into the database ahead of time. These are of the form student_id (foreign key), course_id (foreign key), grades, year (and some other fields). The point is that once a student logs in, their historical grades will be visible. However, the database (initialized as empty by Spring Data JPA) will not let me insert the historical data as it complains that e.g. student_id 1234 (foreign key in the grades table) cannot be found as a primary key in the Students table. Which is true, because I will only create that user 1234 when and if he/she logs in.
I see the following options and don't really like any of them:
disable all constraints on foreign keys for the relevant classes (in which case: How do I tell Spring Data JPA to do that? I googled but couldn't find it) -> Disabling integrity checks sounds like a bad idea though.
Create 'dummy' students, i.e. simply go through the historical data, list all the student_id's and then pre-fill my Student table with entries like student_id = 1234, name = "", address = "", etc. This data would be filled in if/when the students logs in -> This also feels like a 'dirty' solution.
Keep the historical data in .csv files, or another manually created table and have the application load it into the 'real' database only after the student logs in for the first time -> This just sounds like a terrible mess.
Conceptually I'm inclined towards option 1, because I do in fact want to create/save a piece of historical data about a student, despite having no other information about that student. I'm afraid, however, that if I e.g. retrieve all grades for a course_id, those Grade entities will contain links to Student entities that do not in fact exist and this will just result in more errors.
How do you handle such a situation?

Any way to intercept an error message and make more user friendly?

I have looked for an answer here among other places but havent quite been able to find what I need to know.
I have 3 tables, Order_Details, Products_Ordered and Product_Details. The first two are being used in a master detail form to show the order and the items ordered together. The Products_Ordered table has a composite primary key made from two foreign keys, the first being the primary key from the Order_Details table, and the second being the primary key from the Product_Details table. Together they ensure that a type of product can only be added to an order once. If someone wants to order more than one product then the quantity field in the record can be altered to reflect this. All that seems fine so far.
My issue is that when adding products to the order in the master detail form i have used a drop down list of values to select the product to add to the order. the display value for this is the product name and the return value for it is the primary key for the product from the Product_Details table.
I like this because its easier for the user to simply select the product and add a quantity of it to the table. And it works fine for both insert and update operations apart from one situation.
If the user selects the same product in to rows then submits the table the database then tries to add the product to the order twice, throwing a "ORA-00001: unique constraint violated." error. Obviously this is because of the product ID being used in the primary key of the table.
I don't want to allow the user to add two records to the table like that, rather id like to force them to alter the quantity field accordingly. The error message that comes up isn't very user friendly so my question is how can I detect this error and display a more user friendly one instead telling them to alter the quantity field instead?
*If this isn't possible then is there a way that I can hide any already selected products from the dropdown list of values in the following table rows? I haven't looked into this too much because surely it would get complicated when the user tries to add more rows than products available in the dropdown and there are no more products values to show?
I am quite new to this so please be nice. Any help is greatly appreciated :D
Here is a link where all is nicely described:
https://docs.oracle.com/cd/A97630_01/appdev.920/a96624/07_errs.htm
Section
Predefined PL/SQL Exceptions
in combination with:
Defining Your Own PL/SQL Exceptions
and
Defining Your Own Error Messages: Procedure RAISE_APPLICATION_ERROR
Hope it helps...

Create unique constraint on two columns in two tables

Here is my data model.
I need to make the username column in the USER table as a unique column. But it should be unique with the company.
For example, Company A can have a username as James and Company B also can have a username as James.
To achieve this, my opinion is to make a unique constraint with username and company_id.
How can I do this?
You need to change your database adding company_id to users. then add a unique index (company_id,username) to your table.
user
----
user_id (PK)
company_id (UNIQUE INDEX)
emplyee_id
email
username (UNIQUE INDEX)
password
BUT i think you do not need a many to many relation,
could be a good idea to change your database removing the many to many reaction in this way:
company
-------
company_id (PK)
company_name
user
----
user_id (PK)
company_id
emplyee_id
email
username
password
From the data model, it is clear that, a user can belong to multiple companies and a company can have multiple users. So adding company_id to USER table will cause USER table to explode with lots of redundant user data for each company instance. The USER_COMPANY entity exists specifically to avoid this.
It is not advisable to handle this requirement using data model changes. The best way to handle this requirement is through application code or triggers.
The least inefficient way to achieve this through data model changes will be, to add username column in user_company table and synchronise user and user_company table for the user_name column across all DMLs throughout the application. That will again require lots of application code.
So the best solution is to leave it to the application and not disturb a good data model.
Hope this helps.

Validate that value is unique over multiple tables access

Scenario: I have to create a database which has to contain 3 different tables holding information about people. Lets call them Members, Non_Members and Employees. Among the other information they may share , one is the telephone number. The phone numbers are unique, each in its respective table.
My problem: I want to make sure the phone number is always unique among these 3 tables. Is there a way to create a validation rule for that ? If not and I need to redesign the database, which would be the recommended way to do it.
Additional info: While the 3 tables hold the same information (Name , address etc.) its not required always required to fill them. So I am not sure if a generic table named Persons would work for my case.
Some ideas: I was wondering if and how I can use a query as a validation rule (that would make things easier). If I would end up creating a table called Phone numbers , how would the relations between the 4 tables would work in order to ensure that each of the 3 tables has a phone number.
ERD
I assume you are talking about a relational database.
I would go for a single person table with a "type" column (member, non_member, ...). That is much more flexible in the long run. It's easy to add new "person types" - what if you later want a "guest" type?
You would need to define as nullable to cater for the "not all information is required" part.
With just a single table, it's easy to make the phone number unique.
If you do need to make it unique across different tables, you need to put the phone numbers in their own table (where the number is unique) and the references that phone_number table from the other tables.
Edit
Here is an example of creating such a phone_number table:
create table phone_number
(
id integer primary key,
phone varchar(100) not null unique
);
create table member
(
id integer primary key,
name varchar(100),
... other columns
phone_number_id integer references phone_number
);
The tables non_member and employee would have the same structure (which is a strong sign that they should be a single entity)
Edit 2 (2016-01-08 20:12)
As sqlvogel correctly pointed out, putting the phone numbers into a single table doesn't prevent a phone number to be used by more than one person (I misunderstood the requirement so that no phone number should be stored more than once)

Should I store US states as an array or create table columns?

I have an app that houses product data via a Product model and table. Each product has specific state availability (multiple states) that I will need to filter and/or search by in the future. I am hoping to find someone who can tell me the most efficient way to store this data. As I see it, I have two options.
The first is to simply create 50 columns in my table, titled with each state name and containing a boolean value. I can then simply filter by = "avail in California" if product.ca. While this certainly works, it seems a bit cumbersome, especially when searching for multiple state availability.
The second option would be to simply have one column("states") that stores an array of available states and then filter by = "avail in California" if product.states.include? "CA". This seems like a better solution for two reasons. The first, it just allows for a cleaner DB table. Second, and more important, I can allow my user to search by simply saving the user's input as a variable(user_input) and then = "avail in California" if product.states.include? user_input. This solution does call for a little more work up front however when saving the product in the DB, since I won't be able to simply check off a boolean value.
I think option two makes the most sense, but am hoping for some advice as to why or why not. I have found a few similar questions, but they do not seem to explain which solution would be better, just how to accomplish each.
What should I do?
You should normalize unless you have a really good reason not to, and I don't see one in your overview.
To normalize, you should have the following tables:
product table, one record per product
state table, one record per state
product_state table, one entry for every product that is in a state
The product_state schema looks like this:
(product_state_id PK, product_id FK, state_id FK)
UNIQUE INDEX(product_id,state_id);
This allows you to have a product in zero or more states.
I assume that since you’re selling products, you will be charging taxes. There are different taxes by state, county, city. There are country taxes in some countries too.
So you need to abstract these entities into a common parent, usually called GeopoliticalArea, so that you can point a single foreign key (from, say, a tax rates table) at any subtype.
create table geopolitical_area (
id bigint primary key,
type text not null
);
create table country (
id bigint primary key references geopolitical_area(id),
name text not null unique
);
-- represents states/provinces:
create table region (
id bigint primary key references geopolitical_area(id),
name text not null,
country_id bigint references country(id),
unique (name, country_id)
);
insert into geopolitical_area values
(1, 'Country'),
(2, 'Region');
insert into country values
(1, 'United States of America');
insert into region values
(2, 'Alabama', 1);

Resources