Computed column from different tables - sql

I have Broadcasts, Agents and Advert tables:
CREATE TABLE Broadcasts (
Broadcast_code INT IDENTITY(1,1)PRIMARY KEY,
Minute_cost SMALLMONEY NOT NULL
);
CREATE TABLE Agents (
Agent_code INT IDENTITY(1,1)PRIMARY KEY,
Agent_percent FLOAT NOT NULL,
);
CREATE TABLE Advert (
Advert_code INT IDENTITY(1,1)PRIMARY KEY,
Agent_commission AS ((Minute_cost * Duration_in_minutes) / Agent_percent),
Broadcast_code INT FOREIGN KEY REFERENCES Broadcasts (Broadcast_code) NOT NULL,
Agent_code INT FOREIGN KEY REFERENCES Agents (Agent_code) NOT NULL
);
I want to calculate a computed column:
Agent_commission AS (((Minute_cost * Duration_in_minutes) / Agent_percent)
I tried to use VIEWS, TRIGGERS and UDF. But I can't do it.
I need the easiest way because this is a training project.
Thanks.

A computed column cannot directly reference columns in other tables. One option is to write a user-defined scalar function to calculate the commission.
You have two other options:
Use a view instead of a table.
Use a user-defined table function.
Which is best depends on how the commission will be used. I would advise you to start with a view with the logic you want. You may find that you want columns from several tables.

You can follow below steps
Create table
CREATE TABLE Advert (
Advert_code INT IDENTITY(1,1)PRIMARY KEY,
Agent_commission INT,
Broadcast_code INT FOREIGN KEY REFERENCES Broadcasts (Broadcast_code) NOT NULL,
Agent_code INT FOREIGN KEY REFERENCES Agents (Agent_code) NOT NULL
);
Select required columns
SELECT
NULL AS Advert_code,
((B.Minute_cost * Duration_in_minutes) / A.Agent_percent),
B.Broadcast_code,
A.Agent_code
FROM Broadcasts B
INNER JOIN Agents A
ON (B.Broadcast_code = A.Agent_code );
Using the select query, you can insert into new tables
INSERT INTO Advert
SELECT
NULL AS Advert_code,
((B.Minute_cost * Duration_in_minutes) / A.Agent_percent),
B.Broadcast_code,
A.Agent_code
FROM Broadcasts B
INNER JOIN Agents A
ON (B.Broadcast_code = A.Agent_code );
Little clarification,
* From where you are getting Duration_in_minutes
* What is Advert_code, right now am selecting null, if required you can use oracle sequence or select from another table.
You can also use same select query to create views

Related

How to create a projection from multi table

I have 2 tables as following:
CREATE TABLE public.test_employee
(
index int NOT NULL,
name varchar(100),
date_of_birth date,
address varchar(100),
id_dep int NOT NULL,
CONSTRAINT C_PRIMARY PRIMARY KEY (index) DISABLED
);
CREATE TABLE store.test_department
(
index int NOT NULL,
name varchar(100),
describe varchar(100),
CONSTRAINT C_PRIMARY PRIMARY KEY (index) DISABLED
);
I need to create a projection with many columns from the above two tables, My current code looks like this:
CREATE PROJECTION public.employee_department_super
(
idEmp,
idDep,
empName,
date_of_birth,
address,
depName,
describe
)
AS
SELECT e.index,
e.id_dep,
e.name,
e.date_of_birth,
e.address,
d.name,
d.describe
FROM
public.test_employee e
inner join store.test_department d
on e.id_dep=d.index
ORDER BY e.name
UNSEGMENTED ALL NODES;
But I received an error:
[Code: 9366, SQL State: 0A000] [Vertica][VJDBC](9366) ROLLBACK: Projections must select data from only one table
How can I solve this problem?
The answer is: you can't.
Join projections were a thing of a long gone past.
Vertica has begun to satisfy the need of reducing joins by the concept of the flattened table.
You add the two columns as flattened columns to your test_employee table, and they are automatically set whenever you insert new rows into the table.
ALTER TABLE public.test_employee
ADD depname VARCHAR(100)
DEFAULT(
SELECT name FROM store.test_department d WHERE d.index=id_dep
);
ALTER TABLE public.test_employee
ADD describe VARCHAR(100)
DEFAULT(
SELECT describe FROM store.test_department d WHERE d.index=id_dep
);
And the two flattened columns do not count against your license size.

Using sql function on CHECK constraint for newly inserted row

First of all i need help with this for my bachelor thesis. I'm doing the whole database on sql server 2008 Release 2.
The problem is with check constraint that is using a function that is working on her own but not with the use in the constraint. The result of the constraint should be something like this: An employee could go only on one bussines trip per day.
Table Bussines trips:
CREATE TABLE SluzebniCesta(
idSluzCesty int PRIMARY KEY NOT NULL,
DatumCesty DATE NOT NULL,
CasOdjezdu TIME(0) NOT NULL,
CasPrijezdu TIME(0),
CONSTRAINT Odjezd_prijezd CHECK(CasPrijezdu > DATEADD(hour,2,CasOdjezdu))
);
Table that contains the employs that goes on bussines trip:
CREATE TABLE ZamNaCeste(
idZamNaCeste int PRIMARY KEY NOT NULL,
SluzebCestaID int NOT NULL,
ZamestnanecID int NOT NULL,
FOREIGN KEY (ZamestnanecID) REFERENCES Zamestnanec(idZamestnance),
FOREIGN KEY (SluzebCestaID) REFERENCES SluzebniCesta(idSluzCesty)
);
Foreign key ZamestnanecID is an employee's id and SluzebCestaID is the bussines trip id.
Now the function :
CREATE FUNCTION myCheckZamNaCeste(#SluzebCestaID int, #ZamestnanecID int)
RETURNS int
AS
BEGIN
DECLARE #retVal int;
DECLARE #Zamestnanec int;
DECLARE #SluzebniCesta int;
SET #Zamestnanec = (SELECT idZamestnance FROM Zamestnanec WHERE idZamestnance=#ZamestnanecID);
SET #SluzebniCesta = (SELECT idSluzCesty FROM SluzebniCesta WHERE idSluzCesty=#SluzebCestaID);
IF EXISTS ( SELECT DatumCesty FROM SluzebniCesta
WHERE idSluzCesty = #SluzebniCesta
AND DatumCesty IN (SELECT DatumCesty FROM ZamNaCeste
LEFT JOIN SluzebniCesta
ON ZamNaCeste.SluzebCestaID = SluzebniCesta.idSluzCesty
WHERE ZamestnanecID=#Zamestnanec))
BEGIN
SET #retVal=0;
END
ELSE
BEGIN
SET #retVal=1;
END
return #retVal
END
GO
And the alter table for the table that contains evidence of employee and their bussines trips:
ALTER TABLE ZamNaCeste
ADD CONSTRAINT check_cesty_zamestnance CHECK(dbo.myCheckZamNaCeste(SluzebCestaID,ZamestnanecID)=1);
And when I try to enter any new row the constraint is broken even if the function gives the right data. return 1 is the good result ....
In the first place, I'm not sure but it looks like the two set statements in the function are going out to retrieve from tables exactly the same values they already have from being passed in as parameters.
In the second place, I don't see anything limiting trips in the same day. Anywhere.
If you wanted to limit a trip by an employee to one per day, that is easy.
CREATE TABLE ZamNaCeste(
idZamNaCeste int PRIMARY KEY NOT NULL,
SluzebCestaID int NOT NULL,
ZamestnanecID int NOT NULL,
TripDate date not null,
FOREIGN KEY (ZamestnanecID) REFERENCES Zamestnanec(idZamestnance),
FOREIGN KEY (SluzebCestaID) REFERENCES SluzebniCesta(idSluzCesty),
constraint UQ_OneTripPerDay unique( ZamestnanecID, TripDate )
);
The unique constraint ensures the same employee cannot log more than one trip on the same day.
Well in the end i solved with a more sophisticated and better looking solution. The employ is limited with the times of arrival and departure. And i solved it with a function that returns number of incorrect occurences, if its zero than its all right and it works:
SELECT COUNT(*) FROM(SELECT * FROM SluzebniCesta JOIN ZamNaCeste
ON SluzebniCesta.idSluzCesty = ZamNaCeste.SluzebCestaID) AS a
JOIN (SELECT * FROM SluzebniCesta2 JOIN ZamNaCeste
ON SluzebniCesta.idSluzCesty = ZamNaCeste.SluzebCestaID)AS b
ON a.SluzebCestaID b.SluzebCestaID
AND a.CasOdjezdu b.CasOdjezdu
AND a.ZamestnanecID = b.ZamestnanecID
AND (SELECT SluzebniCesta.DatumCesty FROM SluzebniCesta
WHERE SluzebniCesta.idSluzCesty = a.SluzebCestaID) = (SELECT SluzebniCesta.DatumCesty
FROM SluzebniCesta WHERE SluzebniCesta.idSluzCesty = b.SluzebCestaID)

How do you enforce unique across 2 tables in SQL Server

Requirements:
Every employee has a unique ID. (EPID)
A employee can only be either one of below,
FT - Full Time
PT - Part Time
Any employee can never be both FT and PT.
FT & PT have lots of different fields to capture.
Implementation:
Create Table EmpFT( EPID int primary key, F1, F2, etc)
Create Table EmpPT( EPID int primary key, P1, P2, etc)
--This does not prevent same EPID on both EmpFT and EmpPT.
How do you implement No. 3 in database?
I am using SQL Server 2012 standard edition.
Try this method:
CREATE TABLE Emp(EPID INT PRIMARY KEY,
t CHAR(2) NOT NULL, UNIQUE (EPID,t));
CREATE TABLE EmpFT(EPID INT PRIMARY KEY, ... other columns
t CHAR(2) NOT NULL CHECK (t = 'FT'),
FOREIGN KEY (EPID,t) REFERENCES Emp (EPID,t));
CREATE TABLE EmpPT(EPID INT PRIMARY KEY, ... other columns
t CHAR(2) NOT NULL CHECK (t = 'PT'),
FOREIGN KEY (EPID,t) REFERENCES Emp (EPID,t));
You can add check constraints. Something like this for both tables
ALTER TABLE EmpFT
ADD CONSTRAINT chk_EmpFT_EPID CHECK (dbo.CHECK_EmpPT(EPID)= 0)
ALTER TABLE EmpPT
ADD CONSTRAINT chk_EmpPT_EPID CHECK (dbo.CHECK_EmpFT(EPID)= 0)
And the functions like so:
CREATE FUNCTION CHECK_EmpFT(#EPID int)
RETURNS int
AS
BEGIN
DECLARE #ret int;
SELECT #ret = count(*) FROM EmpFT WHERE #EPID = EmpFT.EPID
RETURN #ret;
END
GO
CREATE FUNCTION CHECK_EmpPT(#EPID int)
RETURNS int
AS
BEGIN
DECLARE #ret int;
SELECT #ret = count(*) FROM EmpPT WHERE #EPID = EmpPT.EPID
RETURN #ret;
END
GO
Further reading here:
http://www.w3schools.com/sql/sql_check.asp
http://technet.microsoft.com/en-us/library/ms188258%28v=sql.105%29.aspx
You could create a combined table for all employees. The FT and PT tables could use foreign keys to the employee table.
You cannot have primary keys span tables. So, one method is to create a table employee with the appropriate constraints. This might look like this:
create table employee (
EPID int not null identity(1, 1) primary key,
FTID int references empft(empftid),
PTID int references emppt(empptid),
CHECK (FTID is not null and PTID is null or FTID is null and PTID is not null),
UNIQUE (FTID),
UNIQUE (PTID)
. . .
);
create table empft (
EmpFTId int not null identity(1, 1) primary key,
. . .
);
create table emppt (
EmpPTId int not null identity(1, 1) primary key,
. . .
);
Of course, you could also use triggers if you wanted to.

PL/SQL function that returns a value from a table after a check

I am new to php and sql and I am building a little game to learn a little bit more of the latter.
This is my simple database of three tables:
-- *********** SIMPLE MONSTERS DATABASE
CREATE TABLE monsters (
monster_id VARCHAR(20),
haunt_spawn_point VARCHAR(5) NOT NULL,
monster_name VARCHAR(30) NOT NULL,
level_str VARCHAR(10) NOT NULL,
creation_date DATE NOT NULL,
CONSTRAINT monster_id_pk PRIMARY KEY (monster_id)
);
-- ****************************************
CREATE TABLE spawntypes (
spawn_point VARCHAR(5),
special_tresures VARCHAR (5) NOT NULL,
maximum_monsters NUMBER NOT NULL,
unitary_experience NUMBER NOT NULL,
CONSTRAINT spawn_point_pk PRIMARY KEY (spawn_point)
);
-- ****************************************
CREATE TABLE fights (
fight_id NUMBER,
my_monster_id VARCHAR(20),
foe_spawn_point VARCHAR(5),
foe_monster_id VARCHAR(20) NOT NULL,
fight_start TIMESTAMP NOT NULL,
fight_end TIMESTAMP NOT NULL,
total_experience NUMBER NOT NULL
loot_type NUMBER NOT NULL,
CONSTRAINT my_monster_id_fk FOREIGN KEY (my_monster_id)
REFERENCES monsters (monster_id),
CONSTRAINT foe_spawn_point_fk FOREIGN KEY (foe_spawn_point)
REFERENCES spawntypes (spawn_point),
CONSTRAINT fight_id_pk PRIMARY KEY (fight_id)
);
Given this data how can I easily carry out this two tasks:
1) I would like to create a pl/sql function that passing only a fight_id as a parameter and given the foe_spawn_point (inside the fight table) return the unitary_experience that is related to this spawn point referencing the spawntypes table, how can I do it? :-/ [f(x)]
In order to calculate the total experience earned from a fight (unitary_experience * fight_length) I have created a function that given a particular fight will subtract the fight_end with the fight_start so now I know how long the fight lasted. [f(y)]
2) is it possible to use this two functions (multiply the result that they returns) during the database population task?
INSERT INTO fights VALUES(.... , f(x) * f(y), 'loot A');
in order to populate all the total_experience entries inside the fights table?
thank you for your help
In SQL, you don't generally talk about building functions to do things. The building blocks of SQL are queries, views, and stored procedures (most SQL dialects do have functions, but that is not the place to start).
So, given a variable with $FIGHTID you would fetch the unitary experience with a simple query that uses the join operation:
select unitary_experience
from fight f join
spawnTypes st
on st.spawn_point = f.foe_spawn_point
where fightid = $FIGHTID
If you have a series of values to insert, along with a function, I would recommend using the select form of insert:
insert into fights(<list of columns, total_experience)
select <list of values>,
($FIGHT_END - $FIGHT_START) * (select unitary_experience from spawnTypes where spawnType ='$SPAWN_POINT)
One comment about the tables. It is a good idea for all the ids in the table to be integers that are auto-incremented. In Oracle you do this by creating a sequence (and it is simpler in most other databases).

SQL Server 2008 Foreign Keys that are auto indexed

Are Foreign Keys in SQL Server 2008 are automatically indexed with a value? For Example. if I add a value in my Primary key (or auto incremetend) in may parent table will the table that has a foreign key referenced to that key will automatically have the same value? or I Have to do it explicitly?
No, if you create a foreign key in a child table, it will not automatically get populated when a parent row gets inserted. If you think about this it makes sense. Let's say you have a table like:
CREATE TABLE dbo.Students
(
StudentID INT IDENTITY(1,1) PRIMARY KEY,
Name SYSNAME
);
CREATE TABLE dbo.StudentLoans
(
LoanID INT IDENTITY(1,1) PRIMARY KEY,
StudentID INT FOREIGN KEY REFERENCES dbo.Students(StudentID),
Amount BIGINT -- just being funny
);
What you are suggesting is that when you add a row to Students, the system should automatically add a row to StudentLoans - but what if that student doesn't have a loan? If the student does have a loan, what should the amount be? Should the system pick a random number?
Typically what will happen in this scenario is that you'll be adding a student and their loan at the same time. So if you know the loan amount and the student's name, you can say:
DECLARE
#Name SYSNAME = N'user962206',
#LoanAmount BIGINT = 50000,
#StudentID INT;
INSERT dbo.Students(Name)
SELECT #Name;
SELECT #StudentID = SCOPE_IDENTITY();
INSERT dbo.StudentLoans(StudentID, Amount)
SELECT #StudentID, #LoanAmount;