TYPO3 crdate field in MM table - typo3

I have typo3 7.6.18
#
# Table structure for table 'tx_feusersplus_user_service_mm'
#
CREATE TABLE tx_feusersplus_user_service_mm (
uid_local int(11) unsigned DEFAULT '0' NOT NULL,
uid_foreign int(11) unsigned DEFAULT '0' NOT NULL,
sorting int(11) unsigned DEFAULT '0' NOT NULL,
sorting_foreign int(11) unsigned DEFAULT '0' NOT NULL,
KEY uid_local (uid_local),
KEY uid_foreign (uid_foreign)
);
This is table for MM relation. I want to add crdate field to this table and use it. Field for I can know, when item was added (time). Is it possible ?
I can add this field, but how I can use it ? How to get it in model and in fluid ?

MM tables cannot have any attributes besides the relations to records.
You can however, promote this table to a regular one by adding TCA and using it as regular foreign table instead of MM. The name could then change to tx_feusersplus_user_service. This way your relation table can have all regular table fields.
If you are using an Extbase ObjectStorage here you'll need to change its item type to your new UserService model. That model has one property user and one property service, each with the desired domain model.
One example of such a rich relation table in TYPO3 is sys_file_reference which is basically only a link between records and files but is used explicitly.

Related

Simulate a primary key for a nullable column

I handle members' roles in a table with this structure:
id: id of the row
id_member: integer, foreign key is 'id' column in 'members' table
id_role: integer, foreign key is 'id' column in 'roles' table
date_start: timestamp when this user gets the role
date_end: timestamp when this user loses the role
When I add a role, the date_start is set with current_timestamp, and date_end is null.
When I remove a role, the date_end is set with current_timestamp.
I don't want a user to have several roles at the same time, so initially I thought about setting a triple primary key: id_member, id_role and date_end, but it appears I can't put a nullable column as primary key.
How could I change the structure of the table so that I can prevent a user having 2 active roles? I thought about adding a active column but not only would it overcharge the structure, but also I won't be able to save 2 historical roles (if a user was ROLE3 during 4 different periods, for example).
Thanks in advance.
I don't want a user to have several roles at the same time
Partial UNIQUE index
So, each member can only have a single active role (date_end IS NULL).
A partial UNIQUE index will enforce that:
CREATE UNIQUE INDEX tbl_member_active_role_uni ON tbl (id_member)
WHERE date_end IS NULL; -- active role
See:
Create unique constraint with null columns
PostgreSQL multi-column unique constraint and NULL values
EXCLUDE
The above still allows to add historic entries that overlap. To disallow that, too, use an exclusion constraint. You'll need the additional module btree_gist for your integer column. See:
PostgreSQL EXCLUDE USING error: Data type integer has no default operator class
Then:
ALTER TABLE tbl ADD CONSTRAINT tbl_member_no_overlapping_role
EXCLUDE USING gist (id_member with =, tsrange(date_start, date_end) WITH &&);
NULL values for date_end happen to work perfectly. In a range types, NULL as upper bound signifies "unbounded".
See:
How to ensure entries with non-overlapping time ranges?

What is the best way to work with an optional FK constraint in Postgres? [duplicate]

This question already has answers here:
How can you represent inheritance in a database?
(7 answers)
Closed 3 years ago.
I have a table in Postgres which contains Things. Each of these Things can be of 1 of 3 types:
is a self contained Thing
is an instance of a SuperThingA
is an instance of a SuperThingB.
Essentially, in object terms, there's an AbstractThing, extended in
different ways by SuperThingA or SuperThingB and all the records on
the Thing table are either unextended or extended in 1 of the 2
ways.
In order to represent this on the Thing table, I have a number of fields which are common to Things of all types, and I have 2 optional FK reference columns into the SuperThingA and SuperThingB tables.
Ideally, I would like a "FK IF NOT NULL" constraint on each the two, but this doesn't appear to be possible; as far as I can see, all I can do is make both fields nullable and rely on the using code to maintain the FK relationships, which is pretty sucky. This seems to be doable in other databases, for example SQL Server, as per SQL Server 2005: Nullable Foreign Key Constraint, but not any way that I've found so far in PG
How else can I handle this - an insert/update trigger which checks the values when either of those fields is not null and checks the value is present on whichever parent table? That's maybe doable on a small parent table with limited inserts on the Thing table (which, in fairness, is largely the case here - no more than a couple of hundred records in each of the parent tables, and small numbers of inserts on the Thing table), but in a more general case, would be a performance black hole on the inserts if one or both parent table were large
This is not currently enforced with a FK relationship. I've reviewed the PG docs, and it seem pretty definitive that I can't have an optional FK relatioship (which is understandable). It leaves me with a table definition something like this:
CREATE TABLE IF NOT EXISTS Thing(
Thing_id int4 NOT NULL,
Thing_description varchar(40),
Thing_SuperA_FK int4,
Thing_SuperB_FK char(10),
CONSTRAINT ThingPK PRIMARY KEY (Thing_id)
)
;
Every foreign key on a nullable column is only enforced when the value is non-null. This is default behavior.
create table a (
id int4 not null primary key
);
create table b (
id int4 not null primary key,
a_id int4 references a(id)
);
In the example table b has an optional reference to table a.
insert into a values(1); -- entry in table a
insert into b values (1, 1); -- entry in b with reference to a
insert into b values (2, null); -- entry in b with no reference to a
Depending on your use case it also might make sense to reverse your table structure. Instead of having the common table pointing to two more specialized tables you can have it the other way around. This way you avoid the non-null columns entirely.
create table common(
id int4 primary key
-- all the common fields
);
create table special1(
common_id int4 not null references common(id)
-- all the special fields of type special1
);
create table special2(
common_id int4 not null references common(id)
-- all the special fields of type special2
);
You need your SuperN_FK fields defined as nullable foreign keys, then you'll need check constraint(s) on the table to enforce the optional NULLability requirements.
CREATE TABLE Things
( ID int primary key
, col1 varchar(1)
, col2 varchar(1)
, SuperA_FK int constraint fk_SuperA references Things(ID)
, cola1 varchar(1)
, constraint is_SuperA check ((SuperA_FK is null and cola1 is null) or
(SuperA_FK is not null and cola1 is not null))
, SuperB_FK int constraint fk_SuperB references Things(ID)
, colb1 varchar(1)
, constraint is_SuberB check ((SuperB_FK is null and colb1 is null) or
(SuperB_FK is not null))
, constraint Super_Constraint check (
case when SuperA_FK is not null then 1 else 0 end +
case when SuperB_FK is not null then 1 else 0 end
<= 1 )
);
In the above example I've split the check constraints up for ease maintenance. The two is_SuperN constraints enforce the NULL requirements on the FK and it's related detail columns, either all NULLs or the FK is not null and some or all of the detail columns are not null. The final Super_Constraint ensures that at most one SuperN_FK is not null.

References to multiple tables in PostgreSQL

I have many time series stored in a PostgreSQL database over multiple tables. I would like to create a table 'anomalies' which references to time series with particuliar behaviour, for instance a value that is exceptionally high.
My question is the following: what is the best way to link the entries of 'anomalies' with other tables?
I could create a foreign key in each table referencing to an entry in anomaly, but then it would be not so obvious to go from the anomaly to the entry referencing the anomaly.
The other possibility I see is to store the name of the corresponding table in the entries of anomalies, but it does not seem like a good idea, as the table name might change, or the table might get deleted.
Is there a more elegant solution to do this?
CREATE TABLE type_1(
type_1_id SERIAL PRIMARY KEY,
type_1_name TEXT NOT NULL,
unique(type_1_name)
)
CREATE TABLE type_1_ts(
date DATE NOT NULL,
value REAL NOT NULL,
type_1_id INTEGER REFERENCES type_1(type_1_id) NOT NULL,
PRIMARY KEY(type_1_id, date)
)
CREATE TABLE type_2(
type_2_id SERIAL PRIMARY KEY,
type_2_name TEXT NOT NULL,
unique(type_2_name)
)
CREATE TABLE type_2_ts(
date DATE NOT NULL,
value REAL NOT NULL,
state INTEGER NOT NULL,
type_2_id INTEGER REFERENCES type_2(type_2_id) NOT NULL,
PRIMARY KEY(type_2_id, date)
)
CREATE TABLE anomalies(
anomaly_id SERIAL PRIMARY_KEY,
date DATE NOT NULL,
property TEXT NOT NULL,
value REAL NOT NULL,
-- reference to a table_name and an entry id?
table_name TEXT
data_id INEGER
)
What I'd like to do at the end is to be able to do:
SELECT * FROM ANOMALIES WHERE table_name='type_1',
or simply list the data_type corresponding to the entries

Postgres database inheritance, indexes on child tables

I'm having parent table product and child tables product_1 ... product_N based on field store ID. Once a day UPDATE operation is performed explicitly (and in different time) for all stores. So now I want to add index on some field and I'm not sure which table should have this index. Parent table only or every child table should have its own index? Or both?
UPD
UPDATE product p SET
...
FROM newitems n
WHERE n.new_prod='0' AND
n.internal_product_id is not null AND
p.sku = n.sku AND
p.distributor_id=M and
p.store_id=N;
I want to add index on sku field to make join faster.
Index should be added explicitly on each table. Indexing parent table doesn't affect child tables.
When you first create the child table to can specify to automatically inherit the parent's indexes. (I have not found a way to active this after the child tables is already created).
"The LIKE ... INCLUDING ALL indicates that we will copy in defaults,
primary keys, and index definitions. This now provides a
forward-looking way of managing all notes tables going forward.
Uniqueness criteria remains enforced on a per-table basis." https://dzone.com/articles/table-inheritance-whats-it-good-for
CREATE TABLE notes (
id serial primary key,
created_at timestamp not null default now(),
created_by text not null,
subject text not null,
body text not null,
);
CREATE INDEX idx_notes_subject ON notes (subject);
CREATE TABLE invoice_notes (
child_field text not null,
LIKE notes INCLUDING INDEXES, -- automatically inherit parent indexes
) INHERITS (notes);

If I need to extend mysql.sql a table inside the field ( ejabberd)

If I need to extend mysql.sql a table inside the field, such as users table, the default has the following three fields
username varchar (250) PRIMARY KEY,
password text NOT NULL,
created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
If I need to add an extra field here, like this
username varchar (250) PRIMARY KEY,
password text NOT NULL,
sex tinyint NOT NULL, // note add extra fields here.
created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
So I ejabberd, I do what the job?
Thank you!
You can simply alter your schema to add the extra needed field. It will not be used by ejabberd, but should not cause any issue.