Lookup tables localization - sql

On an project where I use localization I have the following tables:
create table dbo.Posts
(
Id int identity not null primary key clustered (Id),
Created datetime not null,
);
create table dbo.PostsLocalized
(
Id int identity not null primary key clustered (Id),
PostId int not null,
LanguageId int not null,
PostTypeId int not null,
[Text] nvarchar (max) not null,
Title nvarchar (120) not null,
constraint UQ_PostsLocalized_PostId_LanguageId unique (PostId, LanguageId)
);
create table dbo.PostTypes
(
Id int identity not null primary key clustered (Id),
Name nvarchar (max) not null
);
So I am localizing the Posts with a PostsLocalized table but not the PostTypes table.
The PostTypes table is basically a lookup table as others I have in my database.
Do you think I should localize the lookup tables, for example, PostTypes?
I would add a new table named PostTypesLocalized with the localized names.
The same for other lookup tables like Genders, Countries, ...
Or should I localize the lookup tables only in the application?
UPDATE
To clarify:
All localized versions of one post has the same PostType.
I need to display the PostTypes in the UI that is why I need to translate them.
So I tried a new approach following the answer of #dasblinkenlight:
create table dbo.Posts
(
Id int identity not null primary key clustered (Id), -- The id of the localized post
Created datetime not null,
PostId int not null, -- The id of the post
PostTypeId int not null
LanguageId int not null,
[Text] nvarchar (max) not null,
Title nvarchar (120) not null,
constraint UQ_PostsLocalized_PostId_LanguageId unique (PostId, LanguageId)
);
create table dbo.PostTypes
(
Id int identity not null primary key clustered (Id), -- PostType localized id
PostTypeId int not null, -- The id of the post type
Name nvarchar (max) not null
);
Considering (1) then Posts > PostTypeId should be related to PostTypes > PostTypeId.
But how can I do this?

The answer depends on the usage of the Name field of the PostTypes table:
If all uses of that field come from code and/or non-localizable scripts that you may have, localization is not necessary
If the Name makes it to the end-user's view, you should localize the table.
If you need to localize PostTypes, a separate PostTypesLocalized table, in addition to the PostTypes table with locale-independent name, sounds like an appropriate solution.
You should consider the placement of the PostTypeId field, too. Would all localizations with the same PostId refer to the same PostTypeId, or would some of them be different? In case that all localizations of the same Post refer to the same PostType, the field should belong to the Posts table, instead of PostLocalized.
should I localize the lookup tables only in the application?
Adding localization to your database counts as localization of your application. It is a good solution when you contemplate multiple applications using the same database structure.

Related

multiple foreign keys as primary key postgres, should I do it?

This is one of those: why I should or why I should not.
So my books app has reviews, but one user must not review the same book more than one time. In my point of view makes sense to create a table for the reviews and make the user_id and the book_id (ISBN) as the PRIMARY KEY for the reviews table. But, could it be a problem at some point if the application gets too many reviews, for example, could that decision slow the queries?
I am using postgres and I am not sure if the following code is correct:
CREATE TABLE users(
user_id PRIMARY KEY SERIAL,
user_name VARCHAR NOT NULL UNIQUE,
pass_hash VARCHAR NOT NULL,
email VARCHAR NOT NULL UNIQUE,
);
CREATE TABLE books(
book_id PRIMARY KEY BIGINT,
author VARCHAR NOT NULL,
title VARCHAR NOT NULL,
year INT NOT NULL CHECK (year > 1484),
review_count INT DEFAULT 0 NOT NULL,
avrg_score FLOAT,
);
CREATE TABLE reviews(
user_id INT FOREIGN KEY REFERENCES users(user_id) NOT NULL
book_id INT FOREIGN KEY REFERENCES books(book_id) NOT NULL
score INT NOT NULL CHECK (score > 0, score < 11)
PRIMARY KEY (book_id, user_id)
);
This is a perfectly valid design choice.
You have a many-to-many relationship between books and users, which is represented by the reviews table. Having a compound primary key based on two foreign keys lets you enforce referential integrity (a given tuple may only appear once), and at the same time provide a primary key for the table.
Another option would be to have a surrogate primary key for the bridge table. This could make things easier if you need to reference the reviews from another table, but you would still need a unique constraint on both foreign key columns for integrity, so this would actually result in extra space being used.
When it comes to your code, it has a few issues:
the primary key keyword goes after the datatype
the check constraint is incorrectly formed
missing or additional commas here and there
Consider:
CREATE TABLE users(
user_id SERIAL PRIMARY KEY ,
user_name VARCHAR NOT NULL UNIQUE,
pass_hash VARCHAR NOT NULL,
email VARCHAR NOT NULL UNIQUE
);
CREATE TABLE books(
book_id BIGINT PRIMARY KEY,
author VARCHAR NOT NULL,
title VARCHAR NOT NULL,
year INT NOT NULL CHECK (year > 1484),
review_count INT DEFAULT 0 NOT NULL,
avrg_score FLOAT
);
CREATE TABLE reviews(
user_id INT REFERENCES users(user_id) NOT NULL,
book_id INT REFERENCES books(book_id) NOT NULL,
score INT NOT NULL CHECK (score > 0 and score < 11),
PRIMARY KEY (book_id, user_id)
);
I the above is good but I would drop columns review_count and avrg_score from books. These are derivable when needed. If needed for your application then instead of storing these create a view to derive them. This avoids the always complicated process of maintaining running values:
create view books_vw as
select b.book_id
, b.author
, b.title
, b.year
, count(r.*) review_count
, avg(r.score) avrg_score
from books b
left join reviews r
on r.book_id = b.book_id
group by
b.book_id
, b.author
, b.title
, b.year
;

SQL create multiple vs single "statuses tables"

After reviewing many DB designs I'm still not sure what is the best approach.
I am designing a database where most of the entities have different statuses. For example I may have something like
User statuses: Active, Inactive, Disabled, etc.
Order statuses: Open, Close, Canceled;
Office statuses: Open, Close.
And I thinking in two different options.
1) Create one "status" table for every entity
CREATE TABLE UserStatus(
UserStatusID int,
Description varchar(255)
);
CREATE TABLE OrderStatus(
OrderStatusID int,
Description varchar(255)
);
2) Create a single shared status table for all the entities
CREATE TABLE Status(
StatusID int,
Description varchar(255)
);
If you could explain which option is better or the advantanges of each one I would be grateful
Multiple tables have a key advantage: You can declare proper foreign key relationships to ensure that the values are correct in the referenced tables.
A single table has a different advantage: You have all the statuses in one place. This can be quite handy if you need to do something like translate all the statuses into a different language.
In most cases, I think the first advantage outweighs the second. In come cases, however, the second can be important.
One more option - create a single shared status table for all the entities with EntityID.
Something like this:
CREATE TABLE dbo.Entity(
EntityID int NOT NULL
CONSTRAINT PK_Entity PRIMARY KEY CLUSTERED,
Name varchar(50) NOT NULL,
Description varchar(255) NULL,
)
CREATE TABLE dbo.Status(
EntityID int NOT NULL
CONSTRAINT FK_Status_Entity
FOREIGN KEY(EntityID) REFERENCES dbo.Entity (EntityID),
StatusID int NOT NULL,
Name varchar(50) NOT NULL,
Description varchar(255) NULL,
CONSTRAINT PK_Status PRIMARY KEY CLUSTERED (
EntityID ASC,
StatusID ASC)
CONSTRAINT UQ_Status_EntityID_Name UNIQUE NONCLUSTERED (
EntityID ASC,
Name ASC)
)

Determine table structure

I want to create db for anime. This is my ER structure:
https://ibb.co/ctRk8f6
Any tips to improve this?
Every anime has blob for image and relations to brand and episode, each episode may have multiple links and relation to tag.
I wanted to know if this structure is good or should I make separate table for image or any other tip
CREATE TABLE Brand
(
id INT NOT NULL,
name INT NOT NULL,
PRIMARY KEY (id)
);
CREATE TABLE Tag
(
id INT NOT NULL,
name INT NOT NULL,
PRIMARY KEY (id)
);
CREATE TABLE Anime
(
id INT NOT NULL,
name INT NOT NULL,
img INT NOT NULL,
id INT,
PRIMARY KEY (id),
FOREIGN KEY (id) REFERENCES Brand(id)
);
CREATE TABLE Episode
(
order INT NOT NULL,
rating INT NOT NULL,
date INT NOT NULL,
id INT NOT NULL,
PRIMARY KEY (order, id),
FOREIGN KEY (id) REFERENCES Anime(id)
);
CREATE TABLE Link
(
link INT NOT NULL,
host INT NOT NULL,
order INT NOT NULL,
id INT NOT NULL,
PRIMARY KEY (link, order, id),
FOREIGN KEY (order, id) REFERENCES Episode(order, id)
);
CREATE TABLE TagOfAnime
(
id INT NOT NULL,
id INT NOT NULL,
PRIMARY KEY (id, id),
FOREIGN KEY (id) REFERENCES Anime(id),
FOREIGN KEY (id) REFERENCES Tag(id)
);
A few issues here:
Why is everything of type INT? I would assume that name would be a nvarchar of some maximum length nvarchar(200) perhaps?
Your TagOfAnime table has two columns named id. That will not work. If they are references to the primary keys to the tag and Anime tables, then you should name them as such: Tag_id and Anime_id
I would not name a table Link. What is it "linking"? I would make it more descriptive.
In general, add a table if there can be multiple items associated with a single row in another table - as you are doing with the tags for Animes. Otherwise, if the data can appear in additional columns of a single row of the base table, then consolidate your tables to avoid complexity.
Other than that, ask specific questions where you are stuck and I'm sure someone will jump in to help.

Use a common table with many to many relationship

I have two SQL tables: Job and Employee. I need to compare Job Languages Proficiencies and Employee Languages Proficiencies. A Language Proficiency is composed by a Language and a Language Level.
create table dbo.EmployeeLanguageProficiency (
EmployeeId int not null,
LanguageProficiencyId int not null,
constraint PK_ELP primary key clustered (EmployeeId, LanguageProficiencyId)
)
create table dbo.JobLanguageProficiency (
JobId int not null,
LanguageProficiencyId int not null,
constraint PK_JLP primary key clustered (JobId, LanguageProficiencyId)
)
create table dbo.LanguageProficiency (
Id int identity not null
constraint PK_LanguageProficiency_Id primary key clustered (Id),
LanguageCode nvarchar (4) not null,
LanguageLevelId int not null,
constraint UQ_LP unique (LanguageCode, LanguageLevelId)
)
create table dbo.LanguageLevel (
Id int identity not null
constraint PK_LanguageLevel_Id primary key clustered (Id),
Name nvarchar (80) not null
constraint UQ_LanguageLevel_Name unique (Name)
)
create table dbo.[Language]
(
Code nvarchar (4) not null
constraint PK_Language_Code primary key clustered (Code),
Name nvarchar (80) not null
)
My question is about LanguageProficiency table. I added an Id has PK but I am not sure this is the best option.
What do you think about this scheme?
Your constraint of EmployeeId, LanguageProficiencyId allows an employee to have more than one proficiency per language. This sounds counterintuitive.
This would be cleaner, as it allows only one entry per language:
create table dbo.EmployeeLanguageProficiency (
EmployeeId int not null,
LanguageId int not null,
LanguageLevelId int not null,
constraint PK_ELP primary key clustered (EmployeeId, LanguageId)
)
I don't see the point of table LanguageProficiency at the moment.
Same applies to the Job of course. Unless you would like to allow a "range" of proficiencies. But assuming that "too high proficiency" does not hurt, it can easilly be defined through a >= statement in our queries.
Rgds

SQL Server - Create an identifying relationship

I'm currently designing a database to be implemented in SQL Server. I created the following tables without problem:
CREATE TABLE [Client] (
[ClientId] INT NOT NULL,
[Name] VARCHAR(45) NOT NULL,
[IsEnabled] BIT NOT NULL DEFAULT 1,
CONSTRAINT PK_TCASystem PRIMARY KEY CLUSTERED (
ClientId
)
);
CREATE TABLE [Configuration] (
[ConfigId] INT NOT NULL,
[ClientId] INT NOT NULL,
[Name] VARCHAR(45) NOT NULL,
CONSTRAINT PK_Configuration PRIMARY KEY CLUSTERED (
ConfigId, ClientId
),
CONSTRAINT "FK_SystemConfiguration" FOREIGN KEY
(
ClientId
) REFERENCES [Client] (
ClientId
)
);
However, when I tried to add this one:
CREATE TABLE [Mail] (
[MailId] INT NOT NULL,
[ConfigId] INT NOT NULL,
[Recipient] VARCHAR(500) NOT NULL,
[Sender] VARCHAR(50) NOT NULL,
[Subject] VARCHAR(250) NOT NULL,
[Message] TEXT NULL,
CONSTRAINT PK_Mail PRIMARY KEY CLUSTERED (
MailId, ConfigId
),
CONSTRAINT "FK_ConfigurationMail" FOREIGN KEY
(
ConfigId
) REFERENCES [Configuration] (
ConfigId
)
);
I got an error saying that There are no primary or candidate keys in the referenced table 'Configuration' that match the referencing column list in the foreign key 'FK_ConfigurationMail'. I believe this is because the constraint is trying to reference ConfigId, only one half of the composite key, and for this to work I'd need to reference the ClientId too, is that correct?
But my problem is that I first did the design for this database in MYSQL Workbench, and there I indicated that Configuration and Mail, as well as Client and Configuration, have a 1:n identifying relationship (because a Mail instance cannot be created if there isn't a Configuration instance first, and at the same time a Configuration instance cannot exist without having being assigned to a Client first), and as such it created the composite keys for Configuration and Mail. You can see a picture of that here.
So my question is, how can I translate this identifying relationship to SQL Server? Or is that not possible?
EDIT: As suggested I will remove the composite keys from the Configuration table, albeit my question still stands: If I have a 1:n identifying relationship where one of the tables involved uses composite keys, how can I display this on SQL Server? Or is such a case never supposed to happen?
2ND EDIT: To anyone who might come across this question, this post is well worth a read. Cleared up all my confusion in the matter.
Foreign key must reference PK (the entire PK, not portion of PK) or unique index. So add this between create table [Configuration] and [Mail].
CREATE UNIQUE NONCLUSTERED INDEX [UX_Configuration] ON [Configuration]
(
[ConfigId] ASC
)
Check out at sql fiddle for the whole working script:
http://www.sqlfiddle.com/#!3/8877f