Laravel many to many multiple primary key with pivot - laravel

I have a question.
My customer has a database with some tables like this:
Table A
a_id (type uuid, is primary key)
[...]
Table B
b_id (type uuid, is primary key)
[...]
Table AB
a_id (type uuid, is primary key with b_id)
b_id (type uuid, is primary key with a_id)
level (type int) [...]
The relations between A table and B table is many to many.
This is no problem:
// On model A
return $this->belongsToMany('App\Models\B', 'App\Models\AB', 'a_id', 'b_id');
// On model B
return $this->belongsToMany('App\Models\A', 'App\Models\AB', 'b_id', 'a_id');
Now I need get level from table AB at the same time.
I've tried to add
->withPivot('level');
at the end, Something like this:
return $this->belongsToMany('App\Models\A', 'App\Models\AB', 'b_id', 'a_id')->withPivot('level');
If I do this, I get not errors, but level not appears on pivot.
Only appears a_id and b_id.
Someone helps me to obtein level??

Related

SQL Foreign key to two different tables

I have a problem like
Table A:
-- TableBCId
Table B:
-- Id
Table C:
-- Id
I am looking for a way to create a foreign key table A where an entry can be either in table B or table C
Example entries:
Table A:
-- TableBCId: 1
-- TableBCId: 2
Table B:
-- Id: 1
Table C:
-- Id: 2
I want to avoid if possible:
- Two columns in table A
- Default values
- Additional tables
- Creation of an base entity is not possible
Every idea welcome
The normal way to implement this requirement is with 2 columns, 2 foreign key constraints, and a check constraint to ensure exactly of of the columns populated (if this is a requirement):
create table a
( ...
, b_id references b
, c_id references c
, constraint <name> check ( (b_id is null and c_id is not null)
or (b_id is not null and c_id is null)
)
);
You could, if it helps your UI, create a view over that table that combines B_ID and C_ID into a single column.
But you have said you don't want 2 columns, why is that?
The reason why this is hard is because the data model is wrong. A foreign key references only one table. A table can have more than one foreign key but each is separate. Apart from anything else, how would you know whether bc_id referenced b.id or c.id?
One explanation for this scenario is that table A should really be two tables, BA referencing B and CA referencing C. Alternatively A should reference a super-type table, of which B and C are sub-types. Without knowing the actual business domain it's hard to be sure.
Anyway, the path of least change is two columns.
You can use a insert/update trigger on your Table_A.
Maybe something like this:
CREATE TRIGGER Table_a_trgr
BEFORE INSERT OR UPDATE
on Table_a
FOR EACH ROW
DECLARE
c_row NUMBER;
BEGIN
SELECT count(*)
INTO c_row
FROM (
SELECT ID FROM table_b WHERE id = :NEW.TableBCId
UNION ALL
SELECT ID FROM table_c WHERE İd = :NEW.TableBCId
)
;
IF c_row < 2 THEN
raise_application_error(-20000, 'Error, Foreign Key');
END IF;
END;
/
If you don't want to make a new column in table A.
Then you can make a parent table to B and C.
tableBC:
id
And then create a 1-1 relation with tables B and C to table BC.
tableB:
id,
parent -- 1-1 foreign key to tableBC
tableC:
id,
parent -- 1-1 foreign key to tableBC
Now, in table A
tableA:
id,
TableBCId -- foreign key to tableBC
We have solved a similar problem using this approach.

Oracle Insert all data from another table contain duplicates how to avoid

have two tables A and B both same structure except B has one addition extra column inserting as "null". I need to Retain all data from A in B when I insert like below query it is inserting duplicate values because of that getting "primary Key violation error" when I try to create the "CONSTRAINT PK_Details_A PRIMARY KEY" Please help on this to avoid duplicate values while inserting the records.
Thanks in advance.
Insert into tableB(
id, effectiveDate, endDate
,startDate, Type, salary
,baseSalary, Amount, Amount1
,currency, Percentage, Salary
,Notional
)
select id, effectiveDate, endDate
,startDate, Type, salary
,baseSalary, Amount, Amount1
,currency, Percentage, Salary,null
from tableA;
EDIT
Primary key definition for B copied from comment below:
ALTER TABLE B
ADD CONSTRAINT PK_B
PRIMARY KEY ( oid)
USING INDEX ( CREATE UNIQUE INDEX PK_B ON B ( oid )

Why does SQLite not use an index for queries on my many-to-many relation table?

It's been a while since I've written code, and I never used SQLite before, but many-to-many relationships used to be so fundamental, there must be a way to make them fast...
This is a abstracted version of my database:
CREATE TABLE a (_id INTEGER PRIMARY KEY, a1 TEXT NOT NULL);
CREATE TABLE b (_id INTEGER PRIMARY KEY, fk INTEGER NOT NULL REFERENCES a(_id));
CREATE TABLE d (_id INTEGER PRIMARY KEY, d1 TEXT NOT NULL);
CREATE TABLE c (_id INTEGER PRIMARY KEY, fk INTEGER NOT NULL REFERENCES d(_id));
CREATE TABLE b2c (fk_b NOT NULL REFERENCES b(_id), fk_c NOT NULL REFERENCES c(_id), CONSTRAINT PK_b2c_desc PRIMARY KEY (fk_b, fk_c DESC), CONSTRAINT PK_b2c_asc UNIQUE (fk_b, fk_c ASC));
CREATE INDEX a_a1 on a(a1);
CREATE INDEX a_id_and_a1 on a(_id, a1);
CREATE INDEX b_fk on b(fk);
CREATE INDEX b_id_and_fk on b(_id, fk);
CREATE INDEX c_id_and_fk on c(_id, fk);
CREATE INDEX c_fk on c(fk);
CREATE INDEX d_id_and_d1 on d(_id, d1);
CREATE INDEX d_d1 on d(d1);
I have put in any index i could think of, just to make sure (and more than is reasonable, but not a problem, since the data is read only). And yet on this query
SELECT count(*)
FROM a, b, b2c, c, d
WHERE a.a1 = "A"
AND a._id = b.fk
AND b._id = b2c.fk_b
AND c._id = b2c.fk_c
AND d._id = c.fk
AND d.d1 ="D";
the relation table b2c does not use any indexes:
0|0|2|SCAN TABLE b2c
0|1|1|SEARCH TABLE b USING INTEGER PRIMARY KEY (rowid=?)
0|2|0|SEARCH TABLE a USING INTEGER PRIMARY KEY (rowid=?)
0|3|3|SEARCH TABLE c USING INTEGER PRIMARY KEY (rowid=?)
0|4|4|SEARCH TABLE d USING INTEGER PRIMARY KEY (rowid=?)
The query is about two orders of magnitude to slow to be usable. Is there any way to make SQLite use an index on b2c?
Thanks!
In a nested loop join, the outermost table does not use an index for the join (because the database just goes through all rows anyway).
To be able to use an index for a join, the index and the other column must have the same affinity, which usually means that both columns must have the same type.
Change the types of the b2c columns to INTEGER.
If the lookups on a1 or d1 are very selective, using a or d as the outermost table might make sense, and would then allow to use an index for the filter.
Try running ANALYZE.
If that does not help, you can force the join order with CROSS JOIN or INDEXED BY.

How to use Oracle "partitioning by reference" in tables with 2 foreign keys?

A little bit late in the project we have realized that we need to use Oracle (11G) partitioning both for performance and admin of the data.
We have an hierarchical entity model with lots of #OneToMany and #OneToOne relationships, and some entities are referenced from 2 or more other entities.
We want to use "partitioning by range" (month) on the "parent/root" entity and "partition by reference" on all child entities. After a year we will move the oldest month partition to an archive db. It's a 24-7 system so the data continuously grows.
From the Oracle documentation: "Reference partitioning allows the partitioning of two tables related to one another by referential constraints. The partitioning key is resolved through an existing parent-child relationship, enforced by enabled and active primary key and foreign key constraints."
Is it possible to use "partition by reference" on a table when there are 2 foreign keys and one of them can be null?
(From what I read you have to use "not null" on the foreign key for "partition by reference")
A small example to illustrate the problem:
A - parent entity
B - child entity to A
C - child entity to A or B
create table
A (
id number primary key,
adate date
)
partition by range (adate) (
partition p1 values less than (to_date('20130501','yyyymmdd')),
partition p2 values less than (to_date('20130601','yyyymmdd')),
partition pm values less than (maxvalue)
);
create table
B (
id number primary key,
text varchar2(5),
a_id number not null,
constraint fk_ba foreign key (a_id) references A
)
partition by reference(fk_ba);
create table
C (
id number primary key,
text varchar2(5),
a_id number not null, -- NOT POSSIBLE as a_id or b_id will be null..
b_id number not null, -- NOT POSSIBLE as a_id or b_id will be null..
constraint fk_ca foreign key (a_id) references A,
constraint fk_cb foreign key (b_id) references B
)
partition by reference(fk_ca)
partition by reference(fk_cb);
Thanks for any advice.
/Mats
You cannot partition by two foreign keys.
If A is parent of B and B is parent of C i would suggest partitioning C by fk_cb. weather you'l gain max pruning when joining A and C - thats an interesting question, why wont you run a test for us ?
question - why you have FK of A in table C. isn't A implied by the fk to B ?
(my guess, technically it's possible but oracle would have to access table B. i dont think he will do that so i think you wont get prunning).

NHibernate - Composite-Id on relation - Where ID of parent is not same composite

Say I have these table in an Oracle database
Person:
PersonId <- PK ID (int, from sequence)
PersonFirstNameID <-- int
PersonLastNameID <-- int
PersonSecurityID <-- int
PersonDetails
PersonFirstNameID -CompositeKey
PersonLastNameID -CompositeKey
PersonSecurityID -CompositeKey
PersonDetailKey
PersonDetailValue
PersonDetailRisk
Now I want to model the one to many relation from Person to PersonDetails in NHibernate.
How can I do this? I've tried setting up a component representing the composite Id and feeding this into the one to many via the property ref however this generate SQL with duplicate columns and throws the following:
System.ArgumentException: Identifier type mismatch; Found: Expected:
The NHibernate documentation talks only about doing this when the composite Id is the same on both..
Yes... Its not my DB schema, its a legacy DB and access is very limited.
Not quite clear.
For a foreign key relationship to work, the child must reference the primary key of the parent, so the data structure suggests that the primary key of person is FirstNameId/lastNameid/securityid (and hence your best move would be to ignore the personid column).
Is the Person_Id actually the primary key (defined as a PK in the DB), or is the database's version of PERSON primary key actually FirstNameId/lastNameid/securityid ?

Resources