I am working on a PostgreSQL table that takes data from one table and inserts it into another.
i created a table:
create table temp_appearance (firstname text, lastname text, position text, media text);
and populated it with data.
I then created a new table:
create table actors (id serial primary key ,firstname text, lastname text, position text);
But when I insert into actors from temp_appearance:
insert into actors (firstname, lastname, position)
select firstname, lastname, position from temp_appearance;
it gives me this error:
ERROR: COLUMN "firstname" does not exist
HINT: There is a column named "firstname" in table "actors", but it cannot be referenced from this part of the query.
I cant figure out why it is donig this since these same commands have worked on postgreSQL on other computers.
Thanks!
Ok i seem to have figured it out. It doesnt like having the same name for the insert column as well as the from column, so i changed it too
temp_appearance(id serial, fname text, lname text, position text)
which now works since fname and firstname are different column names. Weird i didn't see that in the documentation.
Thanks!
Related
I have a time-series location data table containing the following columns (time, first_name, last_name, loc_lat, loc_long) with the first three columns as the primary key. The table has more than 1M rows.
I notice that first_name and last_name duplicate quite often. There are only 100 combinations in 1M rows. Therefore, to save disk space, I am thinking about creating a separate people table with columns (id, first_name, last_name) where (first_name, last_name) is a unique constraint, in order to simplify the time-series location table to be (time, person_id, loc_lat, loc_long) where person_id is a foreign key for the people table.
I want to first create a new table from my existing 1M row table to test if there is indeed meaningful disk space save with this change. I feel like this task is quite doable but cannot find a concrete way to do so yet. Any suggestions?
That's a basic step of database normalization.
If you can afford to do so, it will be faster to write a new table exchanging full names for IDs, than altering the schema of the existing table and update all rows. Basically:
BEGIN; -- wrap in single transaction (optional, but safer)
CREATE TABLE people (
people_id integer GENERATED ALWAYS AS IDENTITY PRIMARY KEY
, first_name text NOT NULL
, last_name text NOT NULL
, CONSTRAINT full_name_uni UNIQUE (first_name, last_name)
);
INSERT INTO people (first_name, last_name)
SELECT DISTINCT first_name, last_name
FROM tbl
ORDER BY 1, 2; -- optional
ALTER TABLE tbl RENAME TO tbl_old; -- free up org. table name
CREATE TABLE tbl AS
SELECT t.time, p.people_id, t.loc_lat, t.loc_long
FROM tbl_old t
JOIN people p USING (first_name, last_name);
-- ORDER BY ??
ALTER TABLE tbl ADD CONSTRAINT people_id_fk FOREIGN KEY (people_id) REFERENCES people(people_id);
-- make sure the new table is complete. indexes? constraints?
-- Finally:
DROP TABLE tbl_old;
COMMIT;
Related:
Best way to populate a new column in a large table?
Add new column without table lock?
Updating database rows without locking the table in PostgreSQL 9.2
DISTINCT is simple. But for only 100 distinct full names - and with the right index support! - there are more sophisticated, (much) faster ways. See:
Optimize GROUP BY query to retrieve latest row per user
Noob question - Basically I'm trying to get a link table for a many-to-many relationship to auto update. I don't really know if this is what is supposed to happen, but I don't think I'm supposed to manually copy data into it either.
Below is my DDL - if glo.link_table is made this way, and I add data to both glo.collectors and glo.natural_hazards, shouldn't glo.link_table auto-update? Right now glo.link_table is not doing anything when I copy data into to glo.collectors and glo.natural_hazards. I'm guess I'm expecting glo.link_table to like add records when I add data to those two tables.
--Drop if exsits & create
DROP TABLE IF EXISTS glo.collectors CASCADE;
-- Make collectors table
CREATE TABLE glo.collectors (
u_id serial,
user_name text NOT NULL,
password text NOT NULL,
email text NOT NULL,
agency text NOT NULL,
PRIMARY KEY (u_id)
);
--Drop if exsits & create
DROP TABLE IF EXISTS glo.natural_hazards;
-- Create natural hazards table
CREATE TABLE IF NOT EXISTS glo.natural_hazards(
nathaz_id SERIAL,
data_version text,
data_class text, -- class = foundational
agency text NOT NULL,
data_owner text,
data_url text NOT NULL,
keywords text,
spatial_ref text,
creation_date text,
data_description text,
data_purpose text,
fema_sfha text,
event_inundation text,
video_catalog text,
hazard_scale text,
PRIMARY KEY (nathaz_id)
);
--Drop if exsits & create
DROP TABLE IF EXISTS glo.link_table;
-- Create link table
CREATE TABLE IF NOT EXISTS glo.link_table(
u_id int REFERENCES glo.collectors (u_id) ON UPDATE CASCADE ON DELETE CASCADE,
nathaz_id int REFERENCES glo.natural_hazards (nathaz_id) ON UPDATE CASCADE,
CONSTRAINT link_table_pkey PRIMARY KEY (u_id, nathaz_id)
);
No the link_table will not auto populate. Those columns will act in a similar way to a 'foreign key' and ensure that there is some form of constraint on what can be inserted into these columns.
Data that already exists in the link_table will be affected by changes to data in the tables that these columns reference. But this data will have to be inserted separately.
column references documentation
For automatically inserting data into the link_table I would suggest possibly using a trigger.
Trigger documentation
I am new to SQL and am attempted to create a table, then alter the table to add some constraints with ALTER and finally insert 2 employees, one managing the other.
I have been getting this error in pgAdmin4 "ERROR: syntax error at or near "INSERT"
If anyone could let me know any other obvious issues in my code that would be great
Here is the table:
CREATE TABLE employee (
emp_id integer NOT NULL,
first_name varchar(15) NOT NULL,
last_name varchar(15) NOT NULL,
manager integer
);
And the altering:
ALTER TABLE employee ADD CONSTRAINT unique_emp_id UNIQUE (emp_id);
ALTER TABLE employee ADD FOREIGN KEY (manager) REFERENCES emp_id;
ALTER TABLE employee ADD CHECK (emp_id != manager)
INSERT INTO employee VALUES
(1, 'Tom', 'Jones', 2);
INSERT INTO employee (emp_id, first_name, last_name)
VALUES (2, 'Dave', 'Smith');
The foreign key reference needs to mention the table, even for a self-reference:
ALTER TABLE employee ADD FOREIGN KEY (manager) REFERENCES employee(emp_id);
In addition, the first insert doesn't work because the table is empty, so the foreign key fails. The inserts are in the wrong order. You should also list all the columns for an insert, even when you think you know them.
Here is a SQL Fiddle with the rest of the statements working.
Have a table with about 500,000 rows. One of the columns is a string field.
Is there a way to get the set of all existing values of that string in PostgreSQL without having to request each row out of the database and add the values to a set manually?
Example:
first_name last_name
will i.am
will smith
britney spears
The set of all existing values for "first_name" would be ['will', 'britney'].
SELECT DISTINCT first_name FROM people;
or
SELECT first_name FROM people GROUP BY first_name;
I have a table like:
CREATE TABLE test(
id integer not null default nextval('test_id_seq'::regclass),
client_name_id integer not null
);
Foreign-key constraints:
"test_client_name_id_fkey" FOREIGN KEY (client_name_id) REFERENCES company(id) DEFERRABLE INITIALLY DEFERRED
and company table:
CREATE TABLE company(
id integer not null default nextval('company_id_seq'::regclass),
company_name character varying(64) not null
)
Now I have trigger on test table which fetch id from company table using provided value client_name_id which is string by matching it with company_name. but when I insert record PostgreSQL return error that client_name_id is string and int required which is true.
How can I tell PostgreSQL not to verify inserted row as I have taken care of it in my triggers.
What you are trying to do is very unorthodox. Are you sure, this is what you want? Of course, you cant enter a string (with non-digits) into an integer column. No surprise there, right? If you want to enter the text instead, you'd have to add a text column instead - with a fk-constraint to company(company_name) if you want to match your current layout.
ALTER TABLE test ALTER DROP COLUMN client_name_id; -- drops fk constraint, too
ALTER TABLE test ADD COLUMN client_name REFERENCES company(company_name);
You would need a UNIQUE constraint on company.company_name to allow this.
However, I would advise to rethink your approach. Your table layout seems proper as it is. The trigger is the unconventional element. Normally, you would reference the primary key, just like you have it now. No trigger needed. To get the company name, you would join the table in a SELECT:
SELECT *
FROM test t
JOIN company c ON t.client_name_id = c.id;
Also, these non-standard modifiers should only be there if you need them: DEFERRABLE INITIALLY DEFERRED. Like, when you have to enter values in table test before you enter the referenced values in table company (in the same transaction).