SQL SERVER - Violation of UNIQUE KEY Constraint - sql

I'm trying to insert distinct values into a table using INSERT SELECT.
This is my Query
INSERT INTO oltp.Region(Region_Name,Country_Id)
(SELECT DISTINCT region,country_id FROM csv.Neighbourhoods, oltp.Country)
These are the tables
oltp.Country
csv.Neighbourhoods
I want to have a table which shows the Region name and the Country FK in which they come from.
These are the table creations
CREATE TABLE oltp.Country
(Country_Id int NOT NULL PRIMARY KEY IDENTITY(1,1),
Country_Name nvarchar(255) NOT NULL UNIQUE)
CREATE TABLE oltp.Region
(Region_Id int NOT NULL PRIMARY KEY IDENTITY(1,1),
Region_Name nvarchar(255) NOT NULL UNIQUE,
Country_Id int FOREIGN KEY REFERENCES oltp.Country(Country_Id))

You need a JOIN!
INSERT INTO oltp.Region (Region_Name,Country_Id)
SELECT DISTINCT n.region, c.country_id
FROM csv.Neighbourhoods n JOIN
oltp.Country c
ON n.country = c.country_name;
Never use commas in the FROM clause. Always use proper, explicit, standard, readable JOIN syntax.
Also, you should be storing the country id in the Neighbourhoods table, not the name.

Related

how can i create constraint on table based on many column and value in another table Oracle

i have atable such as codes table have these values:
Major_code
minor_code
name
1
0
Country
1
1
USA
1
2
JOR
2
0
Food
2
1
Burger
2
2
Mansaf
I need to create table have these columns (ID, Country_ID , Food_ID) what is the best constraint that resolve this issue?
Having a single lookup table for all reference codes is a very poor design, to the point of almost being a SQL anti-pattern. It is likely to have performance issues. It is also difficult to ensure that the value of COUNTRY_MINOR_CODE references an actual country minor code in the reference table. Which brings us to this statement:
I need to create table have these columns (ID, Country_ID , Food_ID)
Can't be done. Or at least it can be done but you can't build foreign keys on that, because minor keys are not unique in the referenced table. But if you are set on a single table, say lookup_table with primary key defined on (major_code, minor code), you need this:
create table country_food (
id number primary_key
,country_major_code number not null
,country_minor_code number not null
,food_major_code number not null
,food_minor_code number not null
,constraint country_major_code_ck check (country_major_code = 1)
,constraint country_minor_code_ck check (country_minor_code != 0)
,constraint food_major_code_ck check (country_major_code = 2)
,constraint food_minor_code_ck check (country_minor_code != 0)
,constraint country_code_fk foreign key (country_major_code, country_minor_code) references lookup_table
,constraint food_code_fk foreign key (food_major_code, food_minor_code) references lookup_table
)
/
The hard coding of values, the additional check constraints, the increased complexity of joining to look up the name ... These are all reasons why you should choose to have separate tables for FOOD, COUNTRY, etc.
create table country (
country_id number primary_key
,country_name varchar2(24) not null
)
/
create table food (
food_id number primary_key
,food_name varchar2(24) not null
)
/
create table country_food (
id number primary_key
,country_id number not null
,food_id number not null
,food_major_code number not null
,constraint country_code_fk foreign key (country_id) references country
,constraint food_code_fk foreign key (food_id) references food
)
/
If I've got it right, you can get all Country+Food pairs with the query
select t1.minor_code counrty_id, t2.minor_code food_id
from (
select minor_code
from codesTable
where Major_code = (
select c.Major_code
from codesTable c
where c.minor_code=0 and c.name='Country')
) t1
cross join (
select minor_code
from codesTable
where Major_code = (
select c.Major_code
from codesTable c
where c.minor_code=0 and c.name='Food')
) t2
You can use the query to insert data into a table with an autogenerated ID or use it any other way.
First you need to consider the design of the tables
Table of country
Table of foods
Tables of food_country -------- relationship => many-to-many
CREATE TABLE Country
(
Major_code numeric(15) not null,
minor_code numeric(15),
name varchar(50),
CONSTRAINT country_pk PRIMARY KEY (Major_code)
);
CREATE TABLE Food
(
Food_ID numeric(15) not null,
//...........................
name varchar(50),
CONSTRAINT food_pk PRIMARY KEY (Food_ID)
);
CREATE TABLE Counry_Food
(
ID numeric(10) not null,
Country_ID numeric(15) not null,
Food_ID numeric(15) not null,
CONSTRAINT fk_country
FOREIGN KEY (Country_ID)
REFERENCES Country(Major_code),
CONSTRAINT fk_food
FOREIGN KEY (Food_ID)
REFERENCES supplier(Food_ID),
);

Is there a way to relationship between two table which table one has 3 unique keys and table two has 2 unique keys in SQL Server?

I want to create relation between two tables, here's my table structure
Table1:
ID INT PrimaryKey AUTO_INCREMENT,
CountryCode INT UNIQUE,
Division VARCHAR(4) UNIQUE,
SubDivision VARCHAR(10) UNIQUE
Table2:
ID INT PrimaryKey AUTO_INCREMENT,
CountryCode INT UNIQUE,
Division VARCHAR(4) UNIQUE,
ReportNo VARCHAR(10) UNIQUE
Table1:
ID |CountryCode |Division |SubDivision
-------+------------------+--------------+-----------
1 |IDN |A |A-1
2 |IDN |B |B-1
3 |IDN |B |B-2
Table2
ID |CountryCode |Division |ReportNo
-------+------------------+--------------+-----------
1 |IDN |A |Re001
2 |IDN |A |Re002
3 |IDN |B |Re003
I want to create a relationship between those two tables which table2 (CountryCode, Division) refers to table1 (CountryCode, Division).
So when I want to delete in table1 with CountryCode = IDN and Division = A, SQL will prompt error when table2 contains CountryCode = IDN and Division = A.
I had tried to create a relationship between those two tables, but SQL Server always throws this error:
The column in table 'table1' do not match an existing primary key or unique constraint
Can anyone guide me how can I create a relationship between those two tables?
Thanks in advance
You can't do it this way. SQL Server requires a unique constraint (or primary key constraint) on the target of a foreign key - and you have duplicates in the source table.
For this to work, you would need to have a separate table that references all possible (CountryCode, Division) combinations. Actually, your whole schema should be normalized into something like:
-- "top" table that stores the countries
create table countries (
country_id int primary key
name varchar(100)
);
-- the table that stores the divisions
create table divisions (
division_id int primary key,
country_id int references countries(country_id),
name varchar(100)
);
-- the table that stores the subdivisions
-- this corresponds to "table1" in your question
create table subdivisions (
subdivision_id int primary key,
division_id int references divisions(division_id),
name varchar(100)
);
-- the table that stores the reports
-- this corresponds to "table2" in your question
create table reports (
report_id int primary key,
division_id references divisions(division_id),
name varchar(100)
);
You can make the primary keys automatic by using identity columns (which is the SQL Server equivalent for MySQL's AUTO_INCREMENT).
As an example, here is how you would generate the current output that you are showing for the subdivisions:
select
sd.id,
c.name country,
d.name division,
sd.name subdivision
from subdivisions sd
inner join divisions d on d.division_id = sd.division_id
inner join countries c on c.country_id = d.country_id
As GMB has answered you cannot do it in this way because of the duplicates. GMB's answer is the best way to solving your problem. If for some reason you cannot follow his advice then maybe my answer would help.
You could use a composite primary key on the columns CountryCode, Division, SubDivision. Then add subdivision to Table2. And then reference this primary key in the foreignkey restraint. (notice that my example throws an error on purpose to show that the value cannot be deleted)
DROP TABLE IF EXISTS Table2;
DROP TABLE IF EXISTS Table1;
CREATE TABLE Table1
(ID INT IDENTITY(1,1)
, CountryCode CHAR(3)
, Division VARCHAR(4)
, SubDivision VARCHAR(10)
, CONSTRAINT PK_Table1 PRIMARY KEY(CountryCode, Division, SubDivision)
)
INSERT INTO Table1(CountryCode, Division, SubDivision)
VALUES ('IDN', 'A', 'A-1')
, ('IDN', 'B', 'B-1')
, ('IDN', 'B', 'B-2');
CREATE TABLE Table2
(ID INT IDENTITY(1,1) PRIMARY KEY
, CountryCode CHAR(3)
, Division VARCHAR(4)
, SubDivision VARCHAR(10)
, ReportNo VARCHAR(10)
, CONSTRAINT FK_CountryDivision FOREIGN KEY(CountryCode, Division, SubDivision) REFERENCES Table1(CountryCode, Division, SubDivision)
);
INSERT INTO Table2(CountryCode, Division, SubDivision, ReportNo)
VALUES ('IDN', 'A', 'A-1', 'Re001')
, ('IDN', 'B', 'B-1', 'Re002')
, ('IDN', 'B', 'B-2', 'Re003');
DELETE FROM Table1
WHERE Division = 'A';
Of course this change could add a whole set of new problems for instance when a report is for the whole division what should the subdivision value then be.
ps. i had to change up the example tables a bit because the values did not match, ie string values into an int column.
SQL fiddle
thank you for the all greats answer.
But in my design I can't doing this, because I has been wrong at the first time.
And the greats answer was from Mr. #10676716 #GMB.
-- "top" table that stores the countries
create table countries (
country_id int primary key
name varchar(100)
);
-- the table that stores the divisions
create table divisions (
division_id int primary key,
country_id int references countries(country_id),
name varchar(100)
);
-- the table that stores the subdivisions
-- this corresponds to "table1" in your question
create table subdivisions (
subdivision_id int primary key,
division_id int references divisions(division_id),
name varchar(100)
);
-- the table that stores the reports
-- this corresponds to "table2" in your question
create table reports (
report_id int primary key,
division_id references divisions(division_id),
name varchar(100)
);
Thanks again Mr. GMB.

Get columns from one table to another

So I'll create a combination of all first names and all surnames from a table (Person).
insert into tabell_med_navn
select f.fornavn, e.etternavn
from person f cross join person e
These combinations should then be added to a table I have made earlier.
create table tabell_med_navn (
id int not null auto_increment,
fornavn varchar(40) null,
etternavn varchar(40) null,
primary key (id)
);
It is when I am trying to send the combination over it fails. Anybody know why it fails?
List the columns being inserted:
insert into tabell_med_navn (fornavn, etternavn)
select f.fornavn, e.etternavn
from person f cross join
person e;
This will assign a default value to the id column.

Can i use composite primary key here?

Below are my two tables
Student(rno int primary key,name varchar(20))
Fees(id int identity,name varchar(10), amount decimal(10,2), pdate date,
rno int foreign key references Student(rno))
In Fees table [id name rno] gives unique.
So can i create composite primary key on table Fees? or need to add one more table to normalize?
Most of the search on table Fees is based on column rno. So it would be good if i have index on rno.
You can Create Composite Primary Key if you want to be unique set of (id,rno) by below code
create table my_table (
column_a integer not null,
column_b integer not null,
column_c varchar(50),
primary key (column_a, column_b)
);
once you create composite primary key constraint you won't able to insert duplicate combination of rno and id
create one more table of FeesMaster where you entered the which type of fees and its name, if any due, then the price or other details.
This will help in future expansion.
and give reference the FeesMaster id to Fees as FeesID. Always give primary key to auto-increment if it is numeric field.
So your table like this.
Student(rno int primary key with auto-increment,name varchar(20))
FeesMaster(feesid int primary key with auto-increment,name varchar(20), price int, dueprice int) --last 2 is optional or give other detail which work as a master detail
--use this table as a transaction table of both above master table, the logic is
Fees(
id int identity,
rno int foreign key references Student(rno),
feesid id foreign key references FeesMaster(FeesID),
amount decimal(10,2),
pdate date)
Updated :-
Fees
id is primary-key of Fees table which are auto-increment
rno is refernce-key of Student table's rno column
feesid is refernce-key of FeesMaster table's feesid column
So in insert gives the feesid of fees master based on fees name. and to get data, the query looklike
select s.name as studentname, fm.name as feesname
from student s
inner join Fees f on f.rno = s.rno
inner join FeesMaster fm on f.feesid = fm.feesid

How to organize tables to stare statistic of two entities?

For now I have only two tables
CREATE TABLE IF NOT EXISTS company (
id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
name VARCHAR (250) NOT NULL
);
CREATE TABLE IF NOT EXISTS employee (
id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
name VARCHAR (250),
company_id INT,
FOREIGN KEY (company_id) REFERENCES Company (id)
);
I need to create one or two tables to store employees and companies statistic. For employee statistic I need to remember all previous companies of this employee and of cause hire dates and resign dates. For company statistic I need to remember all resigned employees. What is the best way to organize DB structure in my case?
Since you have many-to-many relationship, you need an aggregate table company_employee that will have combined primary key, so you need:
CREATE TABLE IF NOT EXISTS company (
id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
name VARCHAR (250) NOT NULL
);
CREATE TABLE IF NOT EXISTS employee (
id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
name VARCHAR (250)
);
CREATE TABLE IF NOT EXISTS company_employee (
company_id INT NOT NULL,
employee_id INT NOT NULL,
hire_date DATE,
resign_date DATE,
FOREIGN KEY (company_id) REFERENCES Company (id),
FOREIGN KEY (employee_id) REFERENCES Employee (id)
);
So, if you want anything from aggregate table, just use JOIN on key of appropriate table.