Adding Primary Keys in T-SQL - tsql

In a T-SQL tutorial I´ve seen that there are two different ways (at least) of creating or adding a primary key constraint to a table, one of them being making an alteration on the pre-existing table (Customer):
USE RoomReservation;
GO
ALTER TABLE dbo.Customer ADD CONSTRAINT
PK_Customer PRIMARY KEY CLUSTERED (CustomerId);
and the other one being at the moment of creation of the Customer table itself:
USE RoomReservation;
GO
CREATE TABLE dbo.Customer (
CustomerId INT NOT NULL CONSTRAINT PK_Customer PRIMARY KEY,
FirstName NVARCHAR(50) NOT NULL,
LastName NVARCHAR(50) NOT NULL);
My question is :
Are CustomerId and PK_Customer 2 different names for the same primary key atribute?
Are they 2 different attributes that are copies of the same value?
And, either in name or in value, what is the use for this kind of redundance?

Are CustomerId and PK_Customer 2 different names for the same primary key atribute?
No they are not the same. Actually they are two different objects (column != constraint):
CustomerId -- name of column
PK_Customer -- name of constraint
For example if you omit name of PRIMARY KEY constraint it will be autogenerated:
CREATE TABLE dbo.Customer (
CustomerId INT NOT NULL CONSTRAINT PK_Customer PRIMARY KEY,
FirstName NVARCHAR(50) NOT NULL,
LastName NVARCHAR(50) NOT NULL);
SELECT name, object_id, parent_object_id, type_desc
FROM sys.objects
WHERE parent_object_id = OBJECT_ID('dbo.Customer');
┌─────────────┬───────────┬──────────────────┬────────────────────────┐
│ name │ object_id │ parent_object_id │ type_desc │
├─────────────┼───────────┼──────────────────┼────────────────────────┤
│ PK_Customer │ 917578307 │ 901578250 │ PRIMARY_KEY_CONSTRAINT │
└─────────────┴───────────┴──────────────────┴────────────────────────┘
DROP TABLE dbo.Customer;
CREATE TABLE dbo.Customer (
CustomerId INT NOT NULL PRIMARY KEY,
FirstName NVARCHAR(50) NOT NULL,
LastName NVARCHAR(50) NOT NULL);
SELECT name, object_id, parent_object_id, type_desc
FROM sys.objects
WHERE parent_object_id = OBJECT_ID('dbo.Customer');
┌────────────────────────────────┬───────────┬──────────────────┬────────────────────────┐
│ name │ object_id │ parent_object_id │ type_desc │
├────────────────────────────────┼───────────┼──────────────────┼────────────────────────┤
│ PK__Customer__A4AE64D8749AE915 │ 949578421 │ 933578364 │ PRIMARY_KEY_CONSTRAINT │
└────────────────────────────────┴───────────┴──────────────────┴────────────────────────┘
DBFiddle Demo
Are they 2 different attributes that are copies of the same value?
No, they are not copies at all. I guess that it may be confusing because of inline PRIMARY KEY definition. You could make it separate:
CREATE TABLE dbo.Customer (
CustomerId INT NOT NULL ,
FirstName NVARCHAR(50) NOT NULL,
LastName NVARCHAR(50) NOT NULL,
CONSTRAINT PK_Customer PRIMARY KEY -- out of the line
);
Or even on multiple columns(not possible with inline syntax):
CREATE TABLE dbo.InvoiceLine (
InvoiceId INT,
InvoiceLine INT,
Description VARCHAR(100),
CONSTRAINT PK_InvoiceLine PRIMARY KEY(InvoiceId, InvoiceLine)
);

Related

What is wrong with this Query ? PostgreSQL

I want to create 3 tables and join them with foreign keys. Unfortunately, it doesn't work and I have no idea where is a mistake.
CREATE TABLE Students (
Student_Id SERIAL PRIMARY KEY,
Name VARCHAR (20) NOT NULL,
Surname VARCHAR (30) NOT NULL,
Date_of_Birth DATE NOT NULL,
Phone INT NOT NULL UNIQUE,
Email VARCHAR(225) NOT NULL UNIQUE,
Course_Id INT
FOREIGN KEY (Course_Id) REFERENCES Course (Course_Id)
);
CREATE TABLE Course (
Course_Id SERIAL PRIMARY KEY,
Student_Id INT NOT NULL,
Teacher_Id INT NOT NULL,
Category VARCHAR (30) NOT NULL,
FOREIGN KEY (Student_Id) REFERENCES Students (Student_Id)
);
CREATE TABLE Teachers (
Teacher_Id SERIAL PRIMARY KEY,
Name VARCHAR (20) NOT NULL,
Surname VARCHAR (30) NOT NULL,
Phone INT NOT NULL UNIQUE,
Salary INT NOT NULL,
Course_Id INT NOT NULL,
FOREIGN KEY (Teacher_Id) REFERENCES Course (Teacher_Id)
);
I should create a Foreign Key to join all three tables.
I get this error every time: relation "course" does not exist
I can't find where is the mistake. Please help.
It appears like you are attempting to crate a many-to-many (M:M) between Students and Teachers with Course as the resolution table. You are close, however, your definition sets up bi-directional relationships. This is normally not necessary. Define Students and Teachers without the FK to Course. Then define Course with a FK to each.
create table students (
student_id serial primary key
, name varchar (20) not null
, surname varchar (30) not null
, date_of_birth date not null
, phone int not null unique
, email varchar(225) not null unique
);
create table teachers (
teacher_id serial primary key
, name varchar (20) not null
, surname varchar (30) not null
, phone int not null unique
, salary int not null
);
create table course (
course_id serial primary key
, student_id int not null
, teacher_id int not null
, category varchar (30) not null
, foreign key (student_id) references students (student_id)
, foreign key (teacher_id) references teachers (teacher_id)
, unique (student_id, teacher_id)
);
If you must define bi-directional FK in Students and Teachers then create the tables without the FK then use alter table after Course is defined to add the FK and make them DEFERRABLE INITIALLY DEFERRED. Necessary for eventual Inserts.
alter table teachers add column course_id int references course(course_id) deferrable initially deferred;
alter table students add column course_id int references course(course_id) deferrable initially deferred;

Add constraint to table postgresql based on other tables

I have these three tables in postgres database:
create table staff (
e_id int primary key,
first_name text,
last_name text,
job text,
branch_name text);
create table temp_staff (
t_id int primary key,
t_first_name text,
t_last_name text,
t_job text );
create table replacements(
e_id int ,
t_id int,
from_date date,
until_date date,
primary key(e_id, t_id, from_date) );
Now I want to add a constraint to the replacements table so you can insert a replacement with e_id and t_id only if e_id exists in the staff table and t_id exists in the temp_staff table.
I tried this:
alter table replacements
add constraint check_existence
check(exists (select 1 from staff where e_id = e_id) and exists (select 1 from temp_staff where t_id = t_id));
And got the error:
ERROR: cannot use subquery in check constraint
Thanks in advance for any help.

how to retrieve data from multiple tables (postgresql)

I have 4 different tables that are linked to each other in the following way (I only kept the essential columns in each table to emphasise the relationships between them):
create TABLE public.country (
country_code varchar(2) NOT NULL PRIMARY KEY,
country_name text NOT NULL,
);
create table public.address
(
id integer generated always as identity primary key,
country_code text not null,
CONSTRAINT FK_address_2 FOREIGN KEY (country_code) REFERENCES public.country (country_code)
);
create table public.client_order
(
id integer generated always as identity primary key,
address_id integer null,
CONSTRAINT FK_client_order_1 FOREIGN KEY (address_id) REFERENCES public.address (id)
);
create table public.client_order_line
(
id integer generated always as identity primary key,
client_order_id integer not null,
product_id integer not null,
client_order_status_id integer not null default 0,
quantity integer not null,
CONSTRAINT FK_client_order_line_0 FOREIGN KEY (client_order_id) REFERENCES public.client_order (id)
);
I want to get the data in the following way: for each client order line to show the product_id, quantity and country_name(corresponding to that client order line).
I tried this so far:
SELECT country_name FROM public.country WHERE country_code = (
SELECT country_code FROM public.address WHERE id = (
SELECT address_id FROM public.client_order WHERE id= 5
)
)
to get the country name given a client_order_id from client_order_line table. I don't know how to change this to get all the information mentioned above, from client_order_line table which looks like this:
id client_order_id. product_id. status. quantity
1 1 122 0 1000
2 2 122 0 3000
3 2 125 0 3000
4 3 445 0 2000
Thanks a lot!
You need a few join-s.
select col.client_order_id,
col.product_id,
col.client_order_status_id as status,
col.quantity,
c.country_name
from client_order_line col
left join client_order co on col.client_order_id = co.id
left join address a on co.address_id = a.id
left join country c on a.country_code = c.country_code
order by col.client_order_id;
Alternatively you can use your select query as a scalar subquery expression.

Postgres: Create duplicates of existing rows, changing one value?

I am working in Postgres 9.4. I have a table that looks like this:
Column │ Type │ Modifiers
─────────────────┼──────────────────────┼───────────────────────
id │ integer │ not null default
total_list_size │ integer │ not null
date │ date │ not null
pct_id │ character varying(3) │
I want to take all values where date='2015-09-01', and create identical new entries with the date 2015-10-01.
How can I best do this?
I can get the list of values to copy with SELECT * from mytable WHERE date='2015-09-01', but I'm not sure what to do after that.
If the column id is serial then
INSERT INTO mytable (total_list_size, date, pct_id)
SELECT total_list_size, '2015-10-01', pct_id
FROM mytable
WHERE date = '2015-09-01';
else, if you want the ids to be duplicated:
INSERT INTO mytable (id, total_list_size, date, pct_id)
SELECT id, total_list_size, '2015-10-01', pct_id
FROM mytable
WHERE date = '2015-09-01';

Getting a list value for every row (list of ids from another table)

I have a quite ordinary table with a foreign key to another table; for example:
CREATE TABLE table_a (
id serial NOT NULL,
name text,
CONSTRAINT table_a_pkey PRIMARY KEY (id)
);
CREATE TABLE table_b (
id serial NOT NULL,
a_id integer, -- The foreign key
CONSTRAINT table_b_pkey PRIMARY KEY (id),
CONSTRAINT table_b_a_id_fkey FOREIGN KEY (a_id)
REFERENCES table_a (id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION
);
INSERT INTO table_a
VALUES (1, 'First row');
-- 2 entries in table_b which refer to the existing table_a row:
INSERT INTO table_b
VALUES (11, 1), (12, 1);
Now I'd like to have a view which gives me a list of all ids of table_b rows which refer to the current table_a row:
SELECT a.name,
(SELECT b.id
FROM table_b b
WHERE b.id = a.id) AS b_ids
FROM table_a a;
However, the b_ids column is empty; I'd like to have some kind of list there, containing the values 11 and 12.
Somewhere I read that subselects can only yield one column (ok for me in this case) and only one row (which would explain that the above query doesn't work for me). If this is true - how can this be done instead? Or do I really need to issue SELECT requests for every single table_a row in my program?
I'd like this to work with PostgreSQL 9.1 and 9.3.
You can use the array_agg function :
SELECT table_a.name, array_agg(table_b.id)
FROM table_a
LEFT OUTER JOIN table_b
ON table_a.id = table_b.a_id
GROUP BY table_a.name;
┌───────────┬───────────┐
│ name │ array_agg │
├───────────┼───────────┤
│ First row │ {11,12} │
└───────────┴───────────┘
(1 row)
select name
,string_agg(b.id::text,',') b_ids
from table_a join table_b b on table_a.id= b.a_id
group by name