I have a "raw" table that looks like this (among other many fields):
team_id | team_name
---------+-------------------------
1 | Team1
1 | Team1
2 | Team2
2 | Team2
I want to extract the team names and their id codes and create another table for them, so I created:
CREATE TABLE teams (
team_id integer NOT NULL,
team_name varchar(50) NOT NULL,
CONSTRAINT team_pkey PRIMARY KEY (team_id)
);
And I am planning to copy the data from the old table to the recently created one like this:
INSERT INTO teams(team_id,team_name)
SELECT team_id,team_name FROM rawtable
GROUP BY team_id, team_name;
At first I wasn't adding the GROUP BY part, and I was getting a message:
ERROR: duplicate key value violates unique constraint "team_pkey"
I added the GROUP BY so it doesn't try to insert more than one row for the same team, but the problem still persist and I keep getting the same message.
I don't understand what is causing it. It looks like I am inserting single non duplicate rows into the table. What's the best way to fix this?
If two different teams with the same id are in raw_table e.g. (1, 'foo') and (1, 'bar') the group by will still return both, because those two are different.
If you just want to pick one of the rows for duplicate values of team_id then you should use something like this:
insert into teams (team_id,team_name)
select distinct on (team_id) team_id, team_name
from rawtable
order by team_id;
The Postgres specific distinct on operator will make sure that only distinct values for team_id are returned.
My best guess is that you have the same team_id for more then one team_name at least somewhere in your table. Try to add `Having count(*)=1 to your select statement
Since the team_id is unique in the destination table, two separate team names with the same id will create duplicates, one row for each name.
A simple fix is to group by team_id so that you only get a single row per id, and pick one of the names the team has (here we somewhat arbitrarily use MAX to get the last in alphabetical order)
INSERT INTO teams(team_id,team_name)
SELECT team_id, MAX(team_name) FROM rawtable
GROUP BY team_id
One of your Team1 or Team2 probably has some extra spaces or nonprintable characters. This would cause your group by to return multiple rows for Team_ID 1 or 2 causing the problem.
Try to use distinct in your query :
insert into teams (team_id,team_name) select distinct on (team_id)
team_id, team_name from order by team_id;
Related
I ve a Sql table (mariaDB) with 2 Primary keys. I want to remove the rows where the first primary key is duplicated.(yes i know that primary keys cant be duplicated but with 2 Primary keys they work like a touple so that it is possible, but in my case not wanted) example:
id(pk)
name(pk)
smth
smth else
1
a
1234
qwerty
1
b
4567
asdf
and i want to remove the 2nd line cause the id key is duplicated.
tried:
almost any delete query with row count
the query i tried last:
WITH CTE AS
(
SELECT *,ROW_NUMBER() OVER (PARTITION BY id ORDER BY id) AS RN
FROM product_names
)
DELETE FROM CTE WHERE RN<>1
To clarify the definition, you cannot have two primary key in a table. But the primary key of your table is composed of two columns.
To improve your schema, you may want to alter your table so that the primary key is only based on first column. However, depending on the database engine, it can be usefule to keep your composite key. It may speed up query which retrieve the second column only from the primary key. In that case you may want to add a unique clause to the first colume of your primary key.
To cleanup your table you can use that, but beware it doesn't have a filter on the second column, meaning any column with the same id can be deleted depending on its order.
WITH duplicated AS (
SELECT id, name, row_number() OVER (PARTITION BY a) row_number
FROM product_names
ORDER BY name
)
DELETE FROM product_names
WHERE (a, b) IN (SELECT a, b FROM duplicated WHERE row_number > 1);
I Have table three tables:
The first one is emps:
create table emps (id number primary key , name nvarchar2(20));
The second one is cars:
create table cars (id number primary key , car_name varchar2(20));
The third one is accounts:
create table accounts (acc_id number primary key, woner_table nvarchar2(20) ,
woner_id number references emps(id) references cars(id));
Now I Have these values for selected tables:
Emps:
ID Name
-------------------
1 Ali
2 Ahmed
Cars:
ID Name
------------------------
107 Camery 2016
108 Ford 2012
I Want to
Insert values in accounts table so its data should be like this:
Accounts:
Acc_no Woner_Table Woner_ID
------------------------------------------
11013 EMPS 1
12010 CARS 107
I tried to perform this SQL statement:
Insert into accounts (acc_id , woner_table , woner_id) values (11013,'EMPS',1);
BUT I get this error:
ERROR at line 1:
ORA-02291: integrity constraint (HR.SYS_C0016548) violated - parent key not found.
This error occurs because the value of woner_id column doesn't exist in cars table.
My work require link tables in this way.
How Can I Solve This Problem Please ?!..
Mean: How can I reference tables in previous way and Insert values without this problem ?..
One-of relationships are tricky in SQL. With your data structure here is one possibility:
create table accounts (
acc_id number primary key,
emp_id number references emps(id),
car_id number references car(id),
id as (coalesce(emp_id, car_id)),
woner_table as (case when emp_id is not null then 'Emps'
when car_id is not null then 'Cars'
end),
constraint chk_accounts_car_emp check (emp_id is null or car_id is null)
);
You can fetch the id in a select. However, for the insert, you need to be explicit:
Insert into accounts (acc_id , emp_id)
values (11013, 1);
Note: Earlier versions of Oracle do not support virtual columns, but you can do almost the same thing using a view.
Your approach should be changed such that your Account table contains two foreign key fields - one for each foreign table. Like this:
create table accounts (acc_id number primary key,
empsId number references emps(id),
carsId number references cars(id));
The easiest, most straightforward method to do this is as STLDeveloper says, add additional FK columns, one for each table. This also bring along with it the benefit of the database being able to enforce Referential Integrity.
BUT, if you choose not to do, then the next option is to use one FK column for the the FK values and a second column to indicate what table the value refers to. This keeps the number of columns small = 2 max, regardless of number of tables with FKs. But, this significantly increases the programming burden for the application logic and/or PL/SQL, SQL. And, of course, you completely lose Database enforcement of RI.
Quite simply, I need to make a query that prints out all the years (in increasing order) in which only 1 exam took place. I am thinking something along the lines of having to query for every distinct year, and then use the count function to test if there was only one exam in that year? But I can't quite seem to write it out. If it is of importance, the program is being written in Java so I can manipulate outputs.
The form of the EXAM table is:
CREATE TABLE EXAM
(Student_id char(5), NOT NULL
Module_code varchar(6), NOT NULL
Exam_year smallint, NOT NULL
Score smallint, NOT NULL
PRIMARY KEY (Student_id, Module_code) -- Creates a unique tuple
FOREIGN KEY (Student_id) REFERENCES STUDENT(Student_id) -- Enforces data integrity
FOREIGN KEY (Module_code) REFERENCES MODULE(Module_code) -- Enforces data integrity
);
You need to use HAVING, and use distinct Module_code just in case.
SELECT Exam_year
FROM EXAM
GROUP BY Exam_year
HAVING COUNT(distinct Module_code) = 1
ORDER BY Exam_year
select Exam_year
from EXAM
group by module_code
having count(module_code) = 1
order by Exam_year asc
One query should get the job done. Try this:
select Exam_year
from EXAM
group by Exam_year
having count(*) = 1
order by Exam_year
If you need more information than just Exam_year in the output, this can be modified to support additional info, but this example is the simplest way to do what is stated in your requirement.
I have a SELECT query like this:
SELECT id_default_value, id_type FROM ntg_attribute, ntg_module_attribute
WHERE ntg_attribute.id_module_attribute = ntg_module_attribute.id;
This returns 2 columns, id_default_value and id_type. I'd like to then use this data as the basis of an INSERT query into another table, ntg_default_value, using id_default_value as the key, and id_type as the inserted value.
The following is nearly there, but not quite:
INSERT INTO ntg_default_value (id, id_type)
SELECT id_default_value, id_type FROM ntg_attribute, ntg_module_attribute
WHERE ntg_attribute.id_module_attribute = ntg_module_attribute.id;
This gives me:
ERROR: duplicate key value violates unique constraint "pk_ntg_default_value"
Is what I'm trying to do actually possible? If so, how do I construct the query?
(PostgreSQL 8.4.6)
The name of the constraint 'pk_ntg_default_value' probably means you are violating the primary key constraint of the table ntg_default_value.
Depending on your requirements you can either take away the primary key constraint. Or you can expand it to include both id & id_type if it doesn't already and add a GROUP BY to your query, if necessary, to prevent duplicate id_devault_value & id_type pairs. Your query becomes then :
INSERT INTO ntg_default_value (id, id_type)
SELECT id_default_value, id_type
FROM ntg_attribute, ntg_module_attribute
WHERE ntg_attribute.id_module_attribute =
ntg_module_attribute.id
GROUP BY id_default_value, id_type
I have an SQL problem i was wondering if someone could help me out. Below is the schema of the database
Player
playerid (primary key)
playerName
PlaysAt
clubId (primary key)
playerId (fk to PLAYER.playerid)
yearsAtClub
My question is how do i select the clubId of the club where player named john and stephen play where john and stephen play at the same club. I have no idea how to get the club id in this case. i have managed to get the join part correct as im able to select the club id of john but cant get it when i specify the both players using WHERE playerName = john AND playerName = stephen.
Use:
SELECT c.clubid
FROM PLAYSAT c
JOIN PLAYER p ON p.playerid = c.playerid
WHERE p.playername IN ('john', 'stephen')
GROUP BY c.clubid
HAVING COUNT(DISTINCT p.playername) = 2
The key is that the number of parameters in the IN clause needs to match the COUNT in the HAVING clause -- in this case, two.
The DISTINCT helps in case there isn't a primary key or unique constraint on both the PLAYSAT.clubid and PLAYSAT.playerid columns -- two entries for "John" otherwise would be considered valid if for the same clubid value. Otherwise, the DISTINCT can be omitted from the query.
You can join twice to the same table by using the keyword as to create aliases:
select clubId
from PlaysAt
join Player as Player1 using (playerId)
join Player as Player2 using (playerId)
where Player1.playerName = 'john'
and Player2.playerName = 'stephen';
This assumes that the table Player has the primary key playerId (with a capital "I"). It doesn't in your code, but I couldn't tell if this was a typo. If you use the same name for primary key and foreign key you can take advantage of the using keyword, which makes queries much simpler.