Multilingual database design - sql

I'm trying to design a database schema for a multilingual application. I have so far found a sample from this address. http://fczaja.blogspot.com/2010/08/multilanguage-database-design.html
But I haven't understood this sample. Should I insert Id value on app_product first? How can I know that these values are true for ProductId on app_product_translation?
CREATE TABLE ref_language (
Code Char(2)NOT NULL,
Name Varchar(20) NOT NULL,
PRIMARY KEY (Code)
);
CREATE TABLE app_product (
Id Int IDENTITY NOT NULL,
PRIMARY KEY (Id)
);
CREATE TABLE app_product_translation (
ProductId Int NOT NULL,
LanguageCode Char(2) NOT NULL,
Description Text NOT NULL,
FOREIGN KEY (ProductId) REFERENCES app_product(Id),
FOREIGN KEY (LanguageCode) REFERENCES ref_language(Code)
);

It looks like SQLServer code, proceeding on that assumption.
Yes you must insert the app_product first. But you cannot insert the id column's value. It is assigned automatically, because it is an identity column.
Two things you can check out...to find the identity column's value after inserting.
The OUTPUT clause of the INSERT statement. It can return any values that are inserted, not just the identity column.
The ##Identity variable. (by far more traditional and popular)
declare #lastid int
insert into x values (1,2,3)
set #lastid = ##identity
insert into y values (#lastid, a, b, c)

Related

Create an auto incrementing alpha numeric primary key in SQL Server Management Studio

I have a Student table in SQL Server database which is as follows:
CREATE TABLE [dbo].[Student] (
[Id] INT NOT NULL IDENTITY,
[Name] NVARCHAR (50) NOT NULL,
PRIMARY KEY CLUSTERED ([Id] ASC)
);
I want the Id property to be alpha-numeric and auto-increment itself for a new entry. I want Id to be S<number> and then S<number+1> and so on.
I tried to solve this problem as a two-step process:
(i) I first tried to make the Id an auto-incrementing property by doing this:
Then I pressed "Update":
And then I updated again and it led me to this table:
CREATE TABLE [dbo].[Student] (
[Id] INT NOT NULL IDENTITY,
[Name] NVARCHAR (50) NOT NULL,
PRIMARY KEY CLUSTERED ([Id] ASC)
);
I do not think Id is an auto-incrementing value yet. How can I make it both auto-incrementing and alpha-numeric from the following interface:
It seems that you don't really want a fully auto-incrementing alphanumeric column A001,A002...B001, you just want a regular integer column with a prefix of S. For this you can use a simple computed column
ALTER TABLE Student
ADD MyId AS CONCAT('S', Id);

Create enum in SQL Server

In MySQL one can create an enum as such:
USE WorldofWarcraft;
CREATE TABLE [users]
(
ID INT NOT NULL IDENTITY(1,1) PRIMARY KEY,
username varchar(255),
password varchar(255),
mail varchar (255),
rank ENUM ('Fresh meat', 'Intern','Janitor','Lieutenant','Supreme being')DEFAULT 'Fresh meat',
);
This is not possible in SQL Server, so what are the alternatives?
I've read this post
SQL Server equivalent to MySQL enum data type?
Suggesting something like
mycol VARCHAR(10) NOT NULL CHECK (mycol IN('Useful', 'Useless', 'Unknown'))
How can one get that work and create a default value?
The purpose of the enum would be able to tie it to a graphical dropdown on the site which presents the user with values and has a default value pre-specified.
It's better to properly normalize your model:
create table user_rank
(
id integer primary key, -- no identity, so you can control the values
rank varchar(20) not null unique
);
insert into user_rank (id, rank)
values
(1, 'Fresh Meat'),
(2, 'Intern'),
(3, 'Janitor'),
(4, 'Lieutenant'),
(5, 'Supreme being');
CREATE TABLE [users]
(
ID INT NOT NULL IDENTITY(1,1) PRIMARY KEY,
username varchar(255),
password varchar(255),
mail varchar (255),
rank integer not null default 1,
constraint fk_user_rank foreign key (rank) references user_rank (id)
);
The dropdown on your web site can easily be populated by querying the user_rank table.
There is no enum datatype available in SQL Server like in MySQL.
But using the CHECK constraint enum functionality can be implemented.
USE WorldofWarcraft;
CREATE TABLE [users]
(
ID INT NOT NULL IDENTITY(1,1) PRIMARY KEY,
username nvarchar(255),
password nvarchar(255),
mail nvarchar (255),
[rank] nvarchar (255) NOT NULL CHECK ([rank] IN('Fresh meat', 'Intern','Janitor','Lieutenant','Supreme being')) DEFAULT 'Fresh meat'
);

How do I insert data into a row in SQL?

I am following a tutorial and learning MVC from a book, where I was told to create a table using this script, which I did. But now I want to add an entire row to my Pet table, but I am unable to do it.
Script used to create all my tables.
CREATE TABLE [dbo].[Setting] (
[Id] INT NOT NULL IDENTITY(1, 1)
,[Key] VARCHAR(50) NOT NULL
,[Value] VARCHAR(500) NULL
,CONSTRAINT [PK_Setting] PRIMARY KEY ([Id])
);
CREATE TABLE [dbo].[PetType] (
[PetTypeID] INT NOT NULL IDENTITY(1, 1)
,[PetTypeDescription] VARCHAR(50) NULL
,CONSTRAINT [PK_PetType] PRIMARY KEY ([PetTypeID])
);
CREATE TABLE [dbo].[Status] (
[StatusID] INT NOT NULL IDENTITY(1, 1)
,[Description] VARCHAR(50) NOT NULL
,CONSTRAINT [PK_Status] PRIMARY KEY ([StatusID])
);
CREATE TABLE [dbo].[Pet] (
[PetID] INT NOT NULL IDENTITY(1, 1)
,[PetName] VARCHAR(100) NOT NULL
,[PetAgeYears] INT NULL
,[PetAgeMonths] INT NULL
,[StatusID] INT NOT NULL
,[LastSeenOn] DATE NULL
,[LastSeenWhere] VARCHAR(500) NULL
,[Notes] VARCHAR(1500) NULL
,[UserId] INT NOT NULL
,CONSTRAINT [PK_Pet] PRIMARY KEY ([PetID])
,CONSTRAINT [FK_Pet_Status] FOREIGN KEY ([StatusID]) REFERENCES [Status]([StatusID])
,CONSTRAINT [FK_Pet_User] FOREIGN KEY ([UserId]) REFERENCES [UserProfile]([UserId])
);
CREATE TABLE [dbo].[PetPhoto] (
[PhotoID] INT NOT NULL IDENTITY(1, 1)
,[PetID] INT NOT NULL
,[Photo] VARCHAR(500) NOT NULL CONSTRAINT [DF_PhotoFile] DEFAULT '/content/pets/no-image.png'
,[Notes] VARCHAR(500) NULL
,CONSTRAINT [PK_PetPhoto] PRIMARY KEY ([PhotoID])
,CONSTRAINT [FK_PetPhoto_Pet] FOREIGN KEY ([PetID]) REFERENCES [Pet]([PetID])
);
CREATE TABLE [dbo].[Message] (
[MessageID] INT NOT NULL
,[UserId] INT NOT NULL
,[MessageDate] DATETIME NOT NULL
,[From] VARCHAR(150) NOT NULL
,[Email] VARCHAR(150) NOT NULL
,[Subject] VARCHAR(150) NULL
,[Message] VARCHAR(1500) NOT NULL
,CONSTRAINT [PK_Message] PRIMARY KEY ([MessageID])
,CONSTRAINT [FK_Message_User] FOREIGN KEY ([UserId]) REFERENCES [UserProfile]([UserId])
);
I want to add some random values(for testing) into my Pet table's first row.
This is the Pet table's first row as an image for further clarity.
I tried using this script to add values to my table.
INSERT INTO Pet VALUES ('1', 'Fido', '12', '4', '1', '12/07/2004', 'New York', 'nothing', '1')
But I got an error saying
An explicit value for the identity column in table 'Pet' can only be specified when a column list is used and IDENTITY_INSERT is ON.
Now I am fairly new to SQL and I am unable to figure this out. I looked at other SO answers where people said something about SET IDENTITY_INSERT, but this didn't work for me as well. I believe I misunderstood other SO answer since I am fairly new to database languages. So need your help.
Thanks
In SQL Server identity is used for autoincrement. identity(1,1) means the starting value for the column will be 1 and will be incremented by 1. You can change it to desired value for example identity(5,2) starts the value at 5 and increments by 2. You no need to specify an explicit value for setting this column, it will be automatically assigned a unique value.
In mysql you can use AUTO_INCREMENT
Refer w3schools page for details sql autoincrement
PetID is defined as IDENTITY so you cannot specify a value to INSERT in that column unless you set "IDENTITY_INSERT" option to ON.
You have two options:
Dont specify that column/value and let SQL generate it for you.
Set IDENTITY_INSERT to ON before your INSERT operation.
Another very cool way to add rows/edit table (including editting deleting rows) is to use Microsoft SQL Management Studio Express. I didn't know about this until I'd been learning SQL for years. Basically expand the tree structure to the left, right-click on a table and choose Edit Table. When you get going with SQL more, you can edit Stored Procedures in here and pretty much anything SQL else you can can think of.
I've blurred out the actual database names but this gives you the gist of it :-

1 to Many Sql insert

I'm having problems figuring out how to insert a row into my database. I have an experiment table which has the following columns
CREATE TABLE [dbo].[Experiment] (
[ExperimentId] INT IDENTITY (1, 1) NOT NULL,
[Experiment] VARCHAR (100) NOT NULL,
[Account] VARCHAR (100) NOT NULL,
[Profile] VARCHAR (100) NOT NULL,
[Property] VARCHAR (100) NOT NULL,
[BucketId] INT NULL,
CONSTRAINT [PK_Experiment] PRIMARY KEY CLUSTERED ([ExperimentId] ASC),
CONSTRAINT [FK_Experiment_Bucket] FOREIGN KEY (BucketId) REFERENCES Bucket (BucketId)
);
I also have a Bucket table
CREATE TABLE [dbo].[Bucket] (
[BucketId] INT IDENTITY (1, 1) NOT NULL,
[BucketName] CHAR (1) NOT NULL,
CONSTRAINT [PK_BucketId] PRIMARY KEY CLUSTERED ([BucketId] ASC)
);
An experiment can have many buckets (A-Z), however, I'm not really sure how to insert the data.
I'm assuming I have to first insert the bucket information
INSERT INTO Bucket (BucketName) VALUES (#BucketName)
then I would have to insert the data in the experiment table. But how would I get the bucket id from the bucket table when populating the experiment table? Would I just need to do a select statement? Any help would be appreciated.
An experiment can have many buckets (A-Z)
Taking that into consideration, your foreign key is not correct.
You would like to have 1 experiment with N buckets.
In this example, you are having 1 experiment with 1 bucket.
In order to fix this, you'd need to modify Experiment, and remove the BucketId column.
In addition to that, you should add ExperimentId column to Bucket.
And of course, the foreign key constraint.
Once this is done, you will be able to have many buckets per experiment.
-
In order to add rows, you'd have to create the experiment first, and then as many buckets as you want.
Hope this helps.
If an experiment only has one bucket
Declare #bucketID Int;
INSERT INTO [Bucket] (BucketName) VALUES (#BucketName);
set #bucketID = (select SCOPE_IDENTITY());
insert into [Experiment] (bucketID) values (#bucketID);
But this has real problems as it creates a new bucket for each value without checking if the value exists.
What is the actual problem statement?
If this is what you want then just put BucketName in Experiment with no separate table or FK.
If you want an ID and A (as in one) BucketName then:
For this should declare a unique constraint on BucketName
Declare #bucketID Int;
set #bucketID = (select bucketID from bucket where BucketName = #BucketName);
if #bucketID = null;
begin
INSERT INTO [Bucket] (BucketName) VALUES (#BucketName);
set #bucketID = (select SCOPE_IDENTITY());
end
insert into [Experiment] (bucketID) values (#bucketID);
Below assumes a single experiment can have multiple buckets
In the current form it is not 3NF
You would have the problem of repeating data in Experiment and unique [ExperimentId] for each row.
You need a third table for the one to many relationship.
You need a 3rd table ExperimentBucket with a composite PK and FK reference to each table and remove BucketID from Experiment
CREATE TABLE [dbo].[ExperimentBucket] (
[BucketId] INT,
[ExperimentId] INT
CONSTRAINT [PK_BucketId] PRIMARY KEY CLUSTERED ([BucketId] ASC, [ExperimentId] ASC)
CONSTRAINT [FK_ExperimentBucket_Experiment] FOREIGN KEY (ExperimentId)
REFERENCES Experiment(ExperimentId)
CONSTRAINT [FK_ExperimentBucket_Bucket] FOREIGN KEY (BucketId)
REFERENCES Bucket(BucketId)
);
To begin, you have what we call a One-to-many foreign key relationship here: one experiment can have many buckets. In this case the way to set up the keys is that you have a foreign key in Bucket table which refers to the experiment ID.
Since the experiment can have more than one bucket, there will be one row in the experiment table that corresponds to many rows in the bucket table.
CREATE TABLE [dbo].[Experiment] (
[ExperimentId] INT IDENTITY (1, 1) NOT NULL,
[Experiment] VARCHAR (100) NOT NULL,
[Account] VARCHAR (100) NOT NULL,
[Profile] VARCHAR (100) NOT NULL,
[Property] VARCHAR (100) NOT NULL,
// No bucket id[BucketId] INT NULL,
CONSTRAINT [PK_Experiment] PRIMARY KEY CLUSTERED ([ExperimentId] ASC),
);
CREATE TABLE [dbo].[Bucket] (
[BucketId] INT IDENTITY (1, 1) NOT NULL,
[BucketName] CHAR (1) NOT NULL,
[ExperimentId] INT
CONSTRAINT [PK_BucketId] PRIMARY KEY CLUSTERED ([BucketId] ASC)
CONSTRAINT [FK_ExperimentBucket] FOREIGN KEY (ExperimentId)
REFERENCES Experiment(ExperimentId)
);
Once you have that, then you will just Insert the Experiment
INSERT INTO Experiment VALUES (your experiment data)
and then find out what experiment ID you ended up with
SELECT #experimentid = top 1 ExperimentID from Experiments order by ExperimentID
and then insert the buckets with the Bucket ID
INSERT INTO Buckets VALUES (your data with #experimentid)
Yes, you will do a sub-select to get the BucketId from the Bucket table while inserting to Experiment.
INSERT
...
(SELECT TOP 1 BucketId FROM Bucket WHERE BucketName=#BucketName)
...

Need Help Writing SQL Trigger

Been trying to write this trigger but I can't really work it out..
What I need to do:
Delete an item from the item table but at the same time delete any questions which are associated with the item as well as any questionupdates associated with that question. These deleted records then need to be stored in archived tables with a time of deletion as well as the ID of the operator that deleted them.
A question may have several updates associated with it as may an item have many questions relating to it.
I've put all the schema in the SQL fiddle as it's a lot easier to work on in there but I'll put it in here if needed.
The link to the SQL fiddle:
http://sqlfiddle.com/#!1/1bb25
EDIT: Thought I might as well put it here..
Tables:
CREATE TABLE Operator
(
ID INTEGER NOT NULL PRIMARY KEY,
Name VARCHAR(40) NOT NULL
);
CREATE TABLE Item
(
ID INTEGER NOT NULL PRIMARY KEY,
Name VARCHAR(40) NOT NULL
);
CREATE TABLE Faq
(
ID INTEGER NOT NULL PRIMARY KEY,
Question VARCHAR(150) NOT NULL,
Answer VARCHAR(2500) NOT NULL,
ItemID INTEGER,
FOREIGN KEY (ItemID) REFERENCES Item(ID)
);
CREATE TABLE Customer
(
ID INTEGER NOT NULL PRIMARY KEY,
Name VARCHAR(20) NOT NULL,
Email VARCHAR(20) NOT NULL
);
CREATE TABLE Question
(
ID INTEGER NOT NULL PRIMARY KEY,
Problem VARCHAR(1000),
AskedTime TIMESTAMP NOT NULL,
CustomerID INTEGER NOT NULL,
ItemID INTEGER NOT NULL,
FOREIGN KEY (ItemID) REFERENCES Item(ID),
FOREIGN KEY (CustomerID) REFERENCES Customer(ID)
);
CREATE TABLE qUpdate
(
ID INTEGER NOT NULL PRIMARY KEY,
Message VARCHAR(1000) NOT NULL,
UpdateTime TIMESTAMP NOT NULL,
QuestionID INTEGER NOT NULL,
OperatorID INTEGER,
FOREIGN KEY (OperatorID) REFERENCES Operator(ID),
FOREIGN KEY (QuestionID) REFERENCES Question(ID)
);
-- Archive Tables
CREATE TABLE DeletedQuestion
(
ID INTEGER NOT NULL PRIMARY KEY,
Problem VARCHAR(1000),
AskedTime TIMESTAMP NOT NULL,
CustomerID INTEGER NOT NULL,
ItemID INTEGER NOT NULL
);
CREATE TABLE DeletedqUpdate
(
ID INTEGER NOT NULL PRIMARY KEY,
Message VARCHAR(1000) NOT NULL,
UpdateTime TIMESTAMP NOT NULL,
Question INTEGER NOT NULL
);
CREATE TABLE DeletedItem
(
ID INTEGER NOT NULL PRIMARY KEY,
Name VARCHAR(40) NOT NULL,
OperatorDeleteID INTEGER NOT NULL,
FOREIGN KEY (OperatorDeleteID) REFERENCES Operator(ID)
);
Some samples inserts for testing
--Product Inserts
INSERT INTO Item (ID, Name) VALUES (1, 'testitem1');
INSERT INTO Item (ID, Name) VALUES (2, 'testitem2');
--Operator Inserts
INSERT INTO Operator (ID, Name) VALUES (1, 'testname1');
INSERT INTO Operator (ID, Name) VALUES (2, 'testname2');
--Faq Inserts
INSERT INTO Faq (ID, Question, Answer, ItemID) VALUES (1, 'testq1', 'testa1', 1);
INSERT INTO Faq (ID, Question, Answer, ItemID) VALUES (2, 'testq2', 'testa2', 2);
-- Customer Inserts
INSERT INTO Customer (ID, Name, Email) VALUES (1, 'testcust1', 'testemail1');
INSERT INTO Customer (ID, Name, Email) VALUES (2, 'testcust2', 'testemail2');
-- Question Inserts
INSERT INTO Question (ID, Problem, AskedTime, CustomerID, ItemID) VALUES (1,'testproblem1','2012-03-14 09:30',1,1);
INSERT INTO Question (ID, Problem, AskedTime, CustomerID, ItemID) VALUES (2,'testproblem1','2012-07-14 09:30',2,1);
INSERT INTO qUpdate (ID, Message, UpdateTime, OperatorID, QuestionID) VALUES (1, 'test1','2012-05-14 09:30', 1, 1);
INSERT INTO qUpdate (ID, Message, UpdateTime, OperatorID, QuestionID) VALUES (2, 'test2','2012-08-14 09:30', 2, 1);
The first thing to do is to understand that in PostgreSQL, a CREATE TRIGGER statement binds a trigger function to one or more operations on a table, so let's start with the syntax of the function. You can write trigger functions in various scripting languages, but the most common is plpgsql. A simple function might look like this:
CREATE OR REPLACE FUNCTION Question_delete_trig_func()
RETURNS TRIGGER
LANGUAGE plpgsql
AS $$
BEGIN
INSERT INTO DeletedQuestion
SELECT OLD.*;
RETURN OLD;
END;
$$;
To run this after deletes:
CREATE TRIGGER Question_delete_trig
AFTER DELETE ON Question
FOR EACH ROW EXECUTE PROCEDURE Question_delete_trig_func();
That should be enough to get you started.
You should have a trigger like this for each table from which deleted rows should be saved. Then you need to determine how you will make the deletes happen. You could just define the appropriate foreign keys as ON DELETE CASCADE and let PostgreSQL do it for you.