SQL / JPA "conditional" uniqueness a thing? - sql

I have a OneToMany Relation Ship in my entities. There is a entity article an a entity draft.
Every draft has a unique version in connected with an article.
aritcle_id | draft_id | version
-------------------------------
1 | 1 | 1
1 | 2 | 2
1 | 3 | 3
2 | 4 | 1
If I make the version 'unique' it is version-row-far unique is it possible to declare it article-row-far unique? So you can have duplicated versions but only if the version is attached to another article?

Every draft has a unique version
You can implement this with a unique constraint. I think it is:
alter table t add constraint unq_t_draft_version unique (draft_id, version);
If draft_id can be repeated on different articles, you can include all three columns:
alter table t add constraint unq_t_article_draft_version unique (article_id, draft_id, version);

Related

How to dump selected PostgreSQL data from one database to other databse

I have three tables with foreign key relationship with each other.
The table school will be uploaded manually. A student will login to the website and check their marks
The entire data is to be uploaded to another new database of different instance
The Login Id(stud_id) of the student in DB1 is 10 and Login Id(stud_id) of the student in DB2 is 1 in another instance.
For retaining the data of student_marks table, I intend to do the following steps,
1. Dump student_marks table from DB1
2. Copy it to DB2
NOTE: stud_id would be different for both the databases
Is there any way to do the above.
Refer the table below,
school:
id | name| place
-----+-------------
1 | sch1 | test
student:
id | school_id| stud_name
-----+-------------
1 | 1 | stud1
student_marks:
id | stud_id| subj1 | subj2
-----+-----------------------
1 | 1 | 30 | 30
Thanks in advance!
First Disable the foreign key constraint, then dump the data and after that again enable the foreign key constraint or you can put foreign key constraint after migrating the data.

Using 'character' as primary key and reference it from another table

Consider the following postgres (version 9.4) database:
testbase=# select * from employee;
id | name
----+----------------------------------
1 | johnson, jack
2 | jackson, john
(2 rows)
testbase=# select * from worklog;
id | activity | employee | time
----+----------------------------------+----------+----------------------------
1 | department alpha | 1 | 2018-01-27 20:32:16.512677
2 | department beta | 1 | 2018-01-27 20:32:18.112356
5 | break | 1 | 2018-01-27 20:32:22.255563
3 | department gamma | 2 | 2018-01-27 20:32:20.073173
4 | department gamma | 2 | 2018-01-27 20:32:21.05962
(5 rows)
The column 'name' in table 'employee' is of type character(32) and unique, the column 'employee' in 'worklog' references 'id' from the table 'employee'. The column 'id' is the primary key in either table.
I can see all activities from a certain employee by issuing:
testbase=# select * from worklog where employee=(select id from employee where name='johnson, jack');
id | activity | employee | time
----+----------------------------------+----------+----------------------------
1 | department alpha | 1 | 2018-01-27 20:32:16.512677
2 | department beta | 1 | 2018-01-27 20:32:18.112356
5 | break | 1 | 2018-01-27 20:32:22.255563
(3 rows)
I would rather like to simplify the query to
testbase=# select * from worklog where employee='johnson, jack';
For this I would change 'employee' to type character(32) in 'worklog' and declare 'name' as primary key in table 'employee'. Column 'employee' in 'worklog' would, of course, reference 'name' from table 'employee'.
My question:
Will every new row in 'worklog' require additional 32 bytes for name of the 'employee' or will postgres internally just keep a pointer to the foreign field without duplicating the name for every new row?
I suppose that the answer for my question is somewhere in the documentation but I could not find it. It would be very helpful if someone could provide an according link.
PS: I did find this thread, however, there was no link to some official documentation. The behaviour might also have changed, since the thread is now over seven years old.
Postgres will store the data that you tell it to store. There are some new databases that will do compression under the hood -- and Postgres might have features to enable that (I do not know all Postgres features).
But, you shouldn't do this. Integer primary keys are more efficient than strings for three reasons:
They are fixed length in bytes.
They are shorter.
Collations are not an issue.
Stick with your original query, but write it using a join:
select wl.*
from worklog wl join
employee e
on wl.employee = e.id
where e.name = 'johnson, jack';
I suggest this because this is more consistent with how SQL works and makes it easier to choose multiple employees.
If you want to see the name and not the id, create a view (say v_worklog) and add in the employee name.

Postgres / SQL Databases: How to enforce unique combination of key/value Pairs

a new Project requires a dynamic datamodel, meaning that the Properties for a record are stored in a seperate table like this:
Items:
ID | insertiondate
1 | 2017-01-31
Properties:
ID | fk_Item_ID | Key | Value
1 | 1 | referenceNr | 1
2 | 1 | office | O1
...
What i need now is a possibility to enforce that a "referenceNumber" in unique per "office".
so the insertion into this table with the 2 values (1, O2) is ok as well as (2, O1) - but (1, O1) has to violate the Constraint.
Is there a simple way to handle this?
Even if the project really asks for some key/value entries, this doesn't seem to be true for referencenr and office as you want to apply constraints on the pair. So simply put the two in your items table and add the constraint.
The only other option I see is to make the two one entry:
ID | fk_Item_ID | Key | Value
1 | 1 | 'referenceNr/office' | '1/01'
I'd go for the first solution. Have key/value pairs only where absolutely necessary (and where the DBMS may be oblivious as to their content and mutual relations).

How to create a dynamic unique constraint

I have a huge table that is partitioned by a partition id. Each partition can have a different number of fields in its unique constraint. Consider this table:
+----+---------+-------+-----+--+
| id | part_id | name | age | |
+----+---------+-------+-----+--+
| 1 | 1 | James | 12 | |
+----+---------+-------+-----+--+
| 2 | 1 | Mary | 33 | |
+----+---------+-------+-----+--+
| 3 | 2 | James | 1 | |
+----+---------+-------+-----+--+
| 4 | 2 | Mike | 19 | |
+----+---------+-------+-----+--+
| 5 | 3 | James | 12 | |
+----+---------+-------+-----+--+
For part_id: 1 I need a unique constraint on fields name and age. part_id: 2 needs a unique constraint on name. part_id: 3 needs a unique constraint on name. I am open to any database that can accomplish this.
Classic RDBMS is designed to work with stable schema. It means that the structure of your tables, columns, indexes, relations don't change often, each table has a fixed number of columns with fixed types and it is hard/inefficient to make them dynamic.
SQL Server has filtered indexes.
So, you can create a separate unique index for each partition.
CREATE UNIQUE NONCLUSTERED INDEX IX_Part1 ON YourTable
(
name ASC,
age ASC
)
WHERE (part_id = 1)
CREATE UNIQUE NONCLUSTERED INDEX IX_Part2 ON YourTable
(
name ASC
)
WHERE (part_id = 2)
CREATE UNIQUE NONCLUSTERED INDEX IX_Part3 ON YourTable
(
name ASC
)
WHERE (part_id = 3)
These DDL statements are static and the value of part_id is hard coded in them. Optimiser is able to use such indexes in queries that have the same WHERE filter, so they are useful not just for enforcing the constraint.
You can always write a procedure that would generate a text of the CREATE INDEX statement dynamically and run it via EXEC/sp_executesql. There may be some clever use of triggers on YourTable to create it on the fly as the data in your table changes, but in the end it will be some static CREATE INDEX statement.
You can create these indexes in advance for all possible values of part_id, even if there are no such actual values in the table yet.
If you have thousands of part_id and you want to create thousands of such unique constraints, then your current schema may not be quite appropriate.
SQL Server allows max 999 nonclustered indexes per table. See Maximum Capacity Specifications for SQL Server.
Are you trying to build some variation of EAV (entity-attribute-value) model?
Maybe there are non-relational DBMS that allow greater flexibility that would suit better for your task, but I don't have experience with them.
In oracle, the below is possible to create unique index dynamically
CREATE UNIQUE INDEX idx_part_id_dynamic ON partition_table part_id,
(CASE WHEN part_id = 1 THEN name, age
WHEN part_id = 3 THEN age
ELSE height
END );
);

nullable foreign key columns denormalized table vs many normalized tables

In our entitlement framework each "resource" (resource is nothing but any entity that you want to protect by assigning privileges to roles which can access or not access based on privileges) is stored in a resource table like below.
DESIGN1
RESOURCE TABLE
id (int) | namespace (varchar) | entity_id | black_listed (boolean)
1 | com.mycompany.core.entity1 |24 | false
2 | com.mycompany.core.entity2 |24 | false --note entity2
3 | com.mycompany.core.entity10 |3 | false -- note entity10
each resource in the table represent different entity e.g. entity1,entity2,..,entity10. basically that's nothing but entity1.id, entity2.id, entity3.id, ... and so on. because RESOURCE table keeps resources for all kinds of entity - entity_id column in RESOURCE table can't have proper foreign key relationship constraint. we are thinking to refactor this schema such as follow
DESIGN 2
RESOURCE TABLE
id | description | entity1_id | entity2_id | entity3_id | entity4_id | entity5_id | entity6_id | black_listed(boolean)
1 | com.mycompany.core.entity1|24 | null | null | null |null | null
2 | com.mycompany.core.entity2|null | 24 | null | null |null | null
now entity1_id will have a proper FK to entity1 table , entity2_id will have proper FK to entity2 and so on. downside of this approach is that this table will always have null values for all the columns BUT one. e.g. you can only have one entity resource per row. also having null seems to be anti pattern especially for FK relationship. One other way would be normalize the schema and create a resource table for each enitty type. but that will be pretty insane to maintain and quickly become a headache. not saying it's good or bad but doesn't look like a practical design.
is there a better way to design such a table where proper FK relatinoships are also maintained? or you'll endorse Design 2?
You need to create one table for all entities with id (surrogate primary key) or entity_type, entity_id as unique key.
id entity_type entity_id
1 entity1 24
2 entity2 24
Then you need to have only one column in RESOURCE referring to this table (say entities). Your RESOURCE table will look like as in the first example, but the difference is there will be only one entities table, not 10.