Laravel pivot table need to have duplicate entries - mysql

I am using Laravel to build a small customer list system.
I need to link COMPANY with CONTACT_PERSON. In a normal situation, I can use many to many pivot tables to link and update them.
However, I need to keep historical records. That means the same person can act as a contact in the period earlier, resigned, and reappointed later with another period.
I try to duplicate the pivot table entries with phpMyAdmin, makes the same COMPANY linked the same CONTACT_PERSON twice, and two entries were found when retrieving the COMPANY records.
However, how can use Laravel duplicate the entries? How to use Laravel to CURD those. Or I just do it in the wrong way?
Thank you very much!
EDIT :
Example :
Company A employed Mr. A between 01-01-2001 till 02-02-2001,
Compnay A employed Mr. A again on 03-03-2001 till 04-04-2001.
There are company B,C,D ... in company table,
There are Mr. B, C , D in the employee table too.
Use Laravel relationship pivot table to link company A to Mr. A will have two records in the above case (I need to have a historical record).
Is it the right way to handle such cases with Laravel many to many relationships? Or I should consider other ways ?

A pivot table can contain additional columns. You could consider adding migrations that add a started_at and resigned_at datetime field to your pivot table.
Your data structure would look something like this:
Company
id
...
Contact_person_company
contact_person_id
company_id
started_at
resigned_at
Contact person
id
...
After that, you could create functions in your model to work with the pivot columns and check for their status. A null value for the resigned_at column indicates that the ContactPerson is still active.
<?php
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
class Company extends Model
{
// ... other functions
public function contactPersons(): BelongsToMany
{
$this->belongsToMany(Company::class)
->withPivot('started_at', 'resigned_at')
->wherePivotNull('resigned_at');
}
public function resignedContactPersons()
{
$this->belongsToMany(Company::class)
->withPivot('started_at', 'resigned_at')
->wherePivotNotNull('resigned_at');
}
}
You should define these functions as well on the ContactPerson model.
If the logic gets very complicated, consider creating a Pivot model (CompanyContactPerson).
Please note that the combination of contact_person_id, company_id started_at should be unique. Otherwise, considering adding a primary key like ID the company_contact_person table to identify these records.

Related

Database design without a 1 column table

I have been working on a database design and I'm stuck hitting a wall. I'm ending up with what I'm reading is not a normalized database structure but I'm having issues trying to find a "more correct" design and if this design is acceptable how do I execute it in Access?
TLDR: If a table with a single column set as an auto number is an acceptable design, how do you go about inserting a record in it using Access?
The segment of the database of concern is creating a structure for storing companies. Requirements for this is that any changes need to be approved by another user and all historical changes need to be captured so that it can be easily reverted also a company can have multiple aliases but only one legal name.
There is three tables in my solution but one of them is a single column table. From what I've read 95% of people on stack overflow all think its a very bad idea but I've found one post were people are that there are cases for it. I think this is not normal also because I can't find a way to just create a new record in a table with only an auto number column (In Access I have not tried others yet).
Table Structure
Company Names : ID, Company ID, Is Legal Name, Created By, Created On, Approved On, Approved By, Event ID, Is Active
(A company could have a few different names known to the public: TD vs Toronto Dominion. Each name is inserted here with a reference to the company it belongs to)
Companies : ID (Auto Number)
(A company exists and this is its ID)
Companies History : ID, Company ID, Market ID, Holding Company ID, Created By, Created On, Approved On, Approved By, Event ID, Is Active
(These are the historical changes that have been made to the company and who did them and who approved them)
Column Notes:
Event ID : is a FK reference to a table holding each record of actions that have either created, updated or deleted records. (User Research using method [y], Typo Fix, ...)
Is Active : Since deleting records is not possible (historical records need to be kept) this column is used to track if this record is to be included in queries.
Options I see and their issues:
I could get rid of the companies table and make Companies History : ID be the new company id but I find that in that case each time I want to update a company I would need to update each FK reference to the previous company id (I don't think this would be a very normalized approach)
Another Option I see is that I get rid of Companies table and use Company Names : ID as the company id and I would add a column to Company Names called Alias of Company ID. I find that solution adds a log of complexity to my stored data where an alias has company information that differs from the entry that was aliased.
Another Option is that I could add the columns: Created By, Created On, Approved On, Approved By, Event ID and Is Active but this would be duplicating information found in the first record for this company in the Companies History table and this isn't adding any real description to this record.
Anther Option is that I make the Companies table a mirror of Companies History and that when I update or insert a record in Companies I would also insert a record Companies History. With this solution I find that again I duplicate information, that newest record in "Companies History" would hold the same information found in last Inserted or Updated record in in Companies
Another option but is to replace the Companies : ID auto number with a short text and I just get the hash of the current timestamp + a random int. I can now insert new records into this table using access but I feel that this is overkill since I just need the exact same functionality as the auto number.
Another option is move only the legal name into Companies table but now when the legal name of a company changes I have no way of tracking this. Also if I want a list of all names I need to use a union on Companies and Company Names. I find that using unions can reduce performances of queries and I use them only when explicitly needed.
If I don't want to duplicate any information and I don't want to update all FK it seems that I need a table with a single column. If this is acceptable how do I go about inserting a record into a table with a single column set to auto number in Access.
If Companies can be derived from CompanyNames (select distinct CompanyId from CompanyNames), there is no point storing again that information. Just replace that table by a view if you want it (but it as little added value).
On the other hand, if CreatedOn refers to the Company creation (not the row creation) then it is obviously a property of the Company, and I would rather work with
Companies --> Aliases.
But of course I don't know the ins and outs of the reality you're dealing with.

How to design this one to many database?

I've been doing some reading on 'one to many' databases but I'm struggling understand the best way to implement a solution in my case.
I want a MySQL database to record which employees have read certain training hand-outs at work.
So I have a table of Employees. And I have a table of Hand-outs.
I want to record if the Employee has clicked to say they've read the hand-out.
My Employee table has ID, Name, Email.
My Hand-out table has ID, Title
Am I better adding a field to the Employee table that will contain a list of "Hand-out IDs" to show which hand-outs they've read?
I need to be able to easily search to show what percentage of Employees have read a particular hand-out and I think my method would make that very difficult?
I can't have separate fields on the Employee table such as Handout1, Handout2 etc as new hand-outs will be added regularly.
I'm sure this must be a common problem so wondered if someone could direct me to the best solution for this?
Thanks
I think you need a bridge table here which records relationships between employee and hand-out records. Something like this:
Employee_Handout (ID, EmployeeID, HandoutID)
Every time a new handout comes out, you would insert a record into the handout table. Then, when a given employee reads that handout, you would insert a new record into the Employee_Handout table. You probably don't need to persist non-reads, since they could easily be detected as being absent from the bridge table.
The primary key for this column would probably be (EmployeeID, HandoutID), assuming you would only want a single record relating an employee reading a given handout. This would also mean that a given employee/handout relationship could only be persisted once.

How do I add custom records into a query containing a linked table?

I have a linked table that contains descriptive information of restaurants such as name, address, city, etc.
tbl_Restaurant
REST_SITE_CD (PK)
Restaurant
Address
City
…
I have created a query based off of this linked table and a different table that hosts auditing information.
tbl_Audit
AuditID (PK)
REST_ID (FK)
Date
…
From this query, a form was created to allow the user to easily choose a restaurant by its name and location, and enter in the necessary auditing information.
However, some audited restaurants are not located inside tbl_Restaurants. I would like to manually enter these locations into the query, but the query does not allow me to enter new addresses that do not match an existing primary key in tbl_Restaurant.
The only solution I can think of is to create a redundant table just for unlisted restaurants and combine it with the query later on via a union query or something like that. However, I’m sure this violations a bunch of normalization principles. Additionally, it would be ideal if the custom locations are only reflected upon the query and not the linked table, if that makes any sense.
Any help would be appreciated! Please let me know if there’s any other information I can provide.
Records need to be stored in a table.
You can use a local table, and use a UNION ALL to add the records from your local table to the query. However, you can't enter them directly in the query, since union queries are not updateable. You need to add them to the table.

Need help from laravel / query builder masters! trying to filter complicated relationship :(

Table Relationships
orders <-- Has many --> orderdaytimes
orderdaytimes <--belongsToMany--> stores (pivot table name: order_day_time_stores)
Given values & keys
Orders: contains a field called "supplier_id"
Orderdaytimes: contains a field "date"
order_day_time_stores: the pivot table, contains "user_id" and "store_id"
Question
Given "supplier_id", "date" and "store_id", I want to find out which records in the "order_day_time_stores" pivot table meets these criteria.
Can someone give me an idea of how I should go about constructing the query?
Thanks heeeeap :3
Your question could be better. You may want to post your complete Models and / or migrations.
Based on what I understood, this may be what you are looking for:
Assuming you have the models Store, OrderDayTime and Order.
In the Store model, let's assume that your relationship with OrderDayTime is named order_day_times.
Also, in the OrderDayTime model, the relationship with Order is named orders.
$result = Store::find(store_id)
->order_day_times->where('date', date)
->whereHas('orders', function ($q) use (supplier_id) {
$q->where('supplier_id', supplier_id);
})->with('orders')
->get();

Datamapper ORM- Codeigniter Advance Relationship

Please help me to understand the basic use of Datamapper's include_join_fields function. I tried it lots of but not getting any results.
I have application like $object->include_join_fields()
I have User table and Country table.
Please help me to set $hasone=array('country_id'); relation
I haven't any idea about this all, even not getting the exact point after reading documentation of include_join_fields
Any help will appricate
Thanks
include_join_fields are for many to many relationships, where you have a countries_users pivot table, and users could belong to many country.
For example, you could take one user, and the countries, where he belongs to. But you also store, how is a user related to that country. You have to store this extra field in your pivot table: countries_users.
So your pivot table, countries_users will look like something like this, with an example extra field is_he_working_there:
id
country_id
user_id
is_he_working_there
When you make a query for the user's countries, Datamapper won't add that field default. And here comes the include_join_field(), so if you call that, Datamapper will add this field to the end result.
But with hasone, it won't take any effect, because you get the user, and the other table fields also. No pivot table here, so don't need include_join_fields()