SQL: What is does the UNIQUE mean when creating a primary key - sql

I've got a table called students:
+------------+------------+-----------+---------------------+---------------------+
| student_id | first_name | surname | email | reg_date |
+------------+------------+-----------+---------------------+---------------------+
| 1 | Emily | Jackson | emilyj#gmail.com | 2012-10-14 11:14:13 |
| 2 | Daniel | ALexander | daniela#hotmail.com | 2014-08-19 08:08:23 |
| 3 | Sarah | Bell | sbell#gmail.com | 1998-07-04 13:16:32 |
| 4 | Alex | Harte | AHarte#hotmail.com | 1982-06-14 00:00:00 |
+------------+------------+-----------+---------------------+---------------------+
When creating the table:
CREATE TABLE students(
-> student_id INT NOT NULL AUTO_INCREMENT,
-> first_name VARCHAR(30) NOT NULL,
-> surname VARCHAR(50) NOT NULL,
-> email VARCHAR(200) NOT NULL,
-> reg_date DATETIME NOT NULL,
-> PRIMARY KEY (student_id),
-> UNIQUE (email));
What does the 'UNIQUE (email)' mean? Does it mean if the primary key isn't unique, look at the email to see if that's unique instead? Or something different?
Thanks

The UNIQUE keyword creates a unique constraint on the columns that are mentioned in its argument list (in this case, email). It does not interfere with the primary key. It will enforce unique values on the email column, that is, fail with an exception when a row is about to be INSERTed (or UPDATEd) that would collide with an existing row.
A primary key (by default) implies a unique constraint. So as you designate student_id as your primary key, the RDBMS will also automatically maintain unique values in that column for you.
Further reading: http://www.w3schools.com/sql/sql_unique.asp

It allows the engine to use it as an index in queries and enforces it to be unique when a record/s are inserted/updated; throwing a violation of a unique key constraint when an already existing email is inserted/updated.
Example: http://sqlfiddle.com/#!9/7a0aee
More Information: http://dev.mysql.com/doc/refman/5.7/en/partitioning-limitations-partitioning-keys-unique-keys.html

Related

MariaDB foreign key auto generated index not created for the first column of PK

i'm facing a question without answer. I can't understand why the auto generated index from the FK creation is not working when the column seems to be the first one of PK, what i mean :
Create a simple schema with :
CREATE TABLE cat (name VARCHAR(255) PRIMARY KEY);
CREATE TABLE dog (name VARCHAR(255) PRIMARY KEY);
CREATE TABLE cat_dog_couple
(
cat_name VARCHAR(255),
dog_name VARCHAR(255),
PRIMARY KEY (cat_name, dog_name),
CONSTRAINT fk__cat_dog_couple__cat_name FOREIGN KEY (cat_name) references cat(name),
CONSTRAINT fk__cat_dog_couple__dog_name FOREIGN KEY (dog_name) references dog(name)
);
These indexes will be generated :
+----------------+------------+------------------------------+--------------+-------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name |
+----------------+------------+------------------------------+--------------+-------------+
| cat_dog_couple | 0 | PRIMARY | 1 | cat_name |
| cat_dog_couple | 0 | PRIMARY | 2 | dog_name |
| cat_dog_couple | 1 | fk__cat_dog_couple__dog_name | 1 | dog_name |
+----------------+------------+------------------------------+--------------+-------------+
Screen show index
I don't really understand why the index fk__cat_dog_couple__cat_name is not created?
Is it a bug ? A technical limitation ? A technical choice ?
Tested on MariaDB 10.4.x and 10.5.x.

SQL Server Conditional Foreign Key

I have two tables in my SQL Server database, Foo and Bar. Table Foo is like so:
+-------+
| Foo |
+-------+
| Id |
| Type |
| Value |
+-------+
The table has values like:
+----+--------+-----------+
| Id | Type | Value |
+----+--------+-----------+
| 1 | Status | New |
| 2 | Status | Old |
| 3 | Type | Car |
| 4 | State | Inventory |
| 5 | State | Sold |
+----+--------+-----------+
The table Bar is like so:
+----------+
| Bar |
+----------+
| Id |
| TypeId |
| StatusId |
| StateId |
+----------+
Where TypeId, StatusId and StateId are all foreign key'ed to the Foo table.
But I want to put a condition on each foreign key where they can only key to the Foo
ids related to it's type. For example, the TypeId column can ONLY foreign key to id
3 on the Foo table. Or the StatusId column can ONLY foreign key to ids 1 or 2.
I know there is a check function in SQL Server but I'm unsure on how to use it correctly. I
tried to do something like this:
CREATE TABLE TEST.dbo.Bar
(
Id int PRIMARY KEY NOT NULL IDENTITY,
TypeId int NOT NULL CHECK (Type='Type'),
CONSTRAINT FK_Bar_Foo_Type FOREIGN KEY (TypeId) REFERENCES Foo (Id, Type)
)
CREATE UNIQUE INDEX Bar_Id_uindex ON TEST.dbo.Bar (Id)
But this didn't work. What am I doing wrong?
The check constraints you are referring to are only used to limit the type of information stored in a key or non key column. So, if you don't want a key column to have a negative value (lets say its a price column, and there is never a negative price) you will use Check constraint.
To better understand the concept of primary and foreign keys:
Primary key uniquely identifies each record in a table.
Foreign key is a value in some table which is a unique identifier (and can also be a primary key) in another table. This means that Foreign key can repeat many times in the table in which it is a foreign key in, and it will definitely be unique in the table that it is created from ( in the table that gives meaning to it).
Now coming to your question, you probably need to use the concept of composite keys. A composite key is basically a group of two or more values that uniquely identify a record, because you cannot enforce limitations on foreign keys in the way you are intending to do, because that defeats the very purpose of a key. Handle some issues with type of data stored in your keys at the application layer instead of database layer.
Looking at the problem in this manner will conceptually resolve some design flaws with your tables as as well.

How do I enforce referential integrity on a type 6 SCD Dimension table?

I'm having difficulties with designing the Primary and Foreign key relationship between my fact table and a Type 6 SCD Dimension table.
The dimension table has the following definition:
CREATE TABLE DimTable
(
surrogate_key INT,
row_key INT IDENTITY (1,1),
natural_key INT NOT NULL,
current_value INT NOT NULL,
historic_value INT NOT NULL,
is_current BIT NOT NULL,
record_start_date_id INT NOT NULL,
record_end_date_id INT NOT NULL
-- Primary Key
CONSTRAINT pk_dimtable_surrogate_key_row_key PRIMARY KEY (surrogate_key, row_key);
A sample of how the data looks like:
surrogate_key | row_key | natural_key | current_value | historic_value | is_current | record_start_date_id | record_end_date_id
-------------------------------------------------------------------------------------------------------------------------------
121 | 2591227 | 123456 | 20090807 | 20090807 | 0 | 20180807 | 99991231
121 | 2591228 | 123456 | 20140807 | 20090807 | 0 | 20180807 | 99991231
121 | 2591229 | 123456 | 20141107 | 20140807 | 1 | 20180807 | 99991231
122 | 2591230 | 456789 | 20090807 | 20090807 | 1 | 20180807 | 99991231
From my understanding of the wikipedia page, I should be able to enforce Referential integrity through PK/FK relationship, however the master surrogate key is not unique across this table so I don't know how to point the surrogate_id in my fact table to the surrogate_key with a FK constraint.
Is there any way around this limitation, or do I understand the description wrong?
Btw, this is my first time asking a question here, so if anything is unclear or missing please let me know!
EDIT: Column names are generic dummynames. The actual colnames are more descriptive.
I believe you misunderstood the concept of SurrogateKey. Instead the Row_Key attribute here makes more sense of SurrogateKey.
I suggest go one and read books to understand the surrogate key. You may require lot of changes in your process.

Postgres Object-relation database doesn't seem to function properly

I've defined my tables so:
create table device (
id serial primary key,
manufacturerid integer references manufacturer(id) on delete restrict,
model text,
price real,
usagepros text,
usagecons text
);
create table robot (
numaxes integer,
capacity real,
reach real,
accuracy real,
installmethodid integer references installmethod(id) on delete restrict,
mass real
) inherits (device);
create table robotComplex(
id serial primary key,
name text
);
create table robotComplexDevice(
id serial primary key,
deviceId integer references device(id) on delete restrict,
robotcomplexid integer references robotcomplex(id) on delete cascade
);
etc...
I get the following when running sql commands:
id | manufacturerid | model | price | usagepros | usagecons | numaxes | capacity | reach | accuracy | installmethodid | mass
-----+----------------+-------+-------+-----------+-----------+---------+----------+-------+----------+-----------------+-------
159 | 117 | Robot | 100.3 | OK | NoOK | 6 | 15.3 | 15.4 | 76.1234 | 45 | 100.1
> select * from device;
id | manufacturerid | model | price | usagepros | usagecons
-----+----------------+-------+-------+-----------+-----------
159 | 117 | Robot | 100.3 | OK | NoOK
> select * from robotcomplex;
id | name
----+--------------
27 | Complex
> insert into robotcomplexdevice (deviceid, robotcomplexid) values (159, 27);
ERROR: insert or update on table "robotcomplexdevice" violates foreign key constraint "robotcomplexdevice_deviceid_fkey"
DETAIL: Key (deviceid)=(159) is not present in table "device".
For some reason, even though I've defined the "robot" table to inherit "deivice" table, I can't reference it. Maybe I don't get object-relational database model correctly. But if you can't reference the tables so then what is the point of object-relational model?
This is documented behaviour:
http://www.postgresql.org/docs/current/static/ddl-inherit.html#DDL-INHERIT-CAVEATS

How to change a primary key in SQL to auto_increment?

I have a table in MySQL that has a primary key:
mysql> desc gifts;
+---------------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------------+-------------+------+-----+---------+-------+
| giftID | int(11) | NO | PRI | NULL | |
| name | varchar(80) | YES | | NULL | |
| filename | varchar(80) | YES | | NULL | |
| effectiveTime | datetime | YES | | NULL | |
+---------------+-------------+------+-----+---------+-------+
but I wanted to make it auto_increment.
The following statement failed. How can it be modified so that it can work? thanks
mysql> alter table gifts modify giftID int primary key auto_increment;
ERROR 1068 (42000): Multiple primary key defined
Leave off the primary key attribute:
ALTER TABLE gifts MODIFY giftID INT AUTO_INCREMENT;
Certain column attributes, such as PRIMARY KEY, aren't exactly properties of the column so much as shortcuts for other things. A column marked PRIMARY KEY, for example, is placed in the PRIMARY index. Futhermore, all columns in the PRIMARY index are given the NOT NULL attribute. (Aside: to have a multi-column primary key, you must use a separate constraint clause rather than multiple PRIMARY KEY column attributes.) Since the column is already in the PRIMARY index, you don't need to specify it again when you modify the column. Try SHOW CREATE TABLE gifts; to see the affects of using the PRIMARY KEY attribute.