Doing math while updating Postgresql database - postgresql

I am working on a small invoicing solution and I Need to add a column to store the price of one unit. I already have a column for total for all the units and the quantity in the db.
My question is, how can I add this column and populate it with accurate numbers? I know that formula will be:
total_col / quantity_col = unit_col

Here is an example of populating a new column with some derived value:
create table products (
total_col int,
quantity_col int);
ALTER TABLE products ADD COLUMN unit_col numeric(10,2) default null;
update products set unit_col=total_col::float / quantity_col;
You'll want to set up a trigger to keep this column up to date. This is what is know as a persistent, computed column.
Another, perhaps better, solution is to set up a view that has the computed column you want:
create table products (
total_col int,
quantity_col int);
create view productsWithUnitCol as
select *, total_col::float / quantity_col as unit_col from products;

Assuming your database is called mydb, the table is called invoices, and the column is unit_col I would do the following:
Connect to your postgresql database via command line, typically psql mydb and then the following:
ALTER TABLE invoices
ADD COLUMN unit_col real;
UPDATE invoices SET unit_col = total_col/quantity_col;

Related

Convert multiple columns to timestamp from unix seconds and add it to the existing table as two new columns in Postgresql

I am new to postgresql, I am trying to convert two columns into timestamp from unix seconds and adding as new columns. But I am not sure how to correct this.
SELECT arrival_unix_seconds,departure_unix_seconds,to_timestamp(arrival_unix_seconds) as arrival FROM public."Operation"
alter table add column arrival timestamp;
I can only do it for one column and just display the result but can't add it to the table.
Also want to find the time difference between the two resultant columns in minutes.
The data looks like,
arrival_unix_seconds departure_unix_seconds
1619808731; 1619809039;
1619808082; 1619808711;
1619807810; 1619809705;
1619807573; 1619808556;
1619807394; 1619808623;
First alter the table and add the two columns.
ALTER TABLE public."Operation"
ADD COLUMN arrival timestamp,
ADD COLUMN departure timestamp;
Then use UPDATE to copy the converted timestamps into the new columns.
UPDATE public."Operation"
SET arrival = to_timestamp(arrival_unix_seconds),
departure = to_timestamp(departure_unix_seconds);
And, since you now have columns directly depending on other columns in the table, you should drop the old columns to normalize the table again.
ALTER TABLE public."Operation"
DROP COLUMN arrival_unix_seconds,
DROP COLUMN departure_unix_seconds;
You should also consider not to use case sensitive identifiers like table names. They just make things more complicated than necessary. And identifiers in the database don't need to be "pretty". That's a job for the presentation layer.
You can use below queries for your problem
alter table public."Operation" add column arrival timestamp;
update public."Operation" set arrival=to_timestamp(arrival_unix_seconds);
alter table public."Operation" add column departure timestamp;
update public."Operation" set departure=to_timestamp(departure_unix_seconds);
To calculate difference in minutes you can use following methods:
If you want to keep the columns departure_unix_seconds and arrival_unix_seconds then
select (departure_unix_seconds - arrival_unix_seconds)/60 "Difference" from public."Operation";
If you want to use newly created columns then
select extract( epoch from (departure - arrival))::integer/60 "Difference" from public."Operation";

PostgreSQL id column not defined

I am new in PostgreSQL and I am working with this database.
I got a file which I imported, and I am trying to get rows with a certain ID. But the ID is not defined, as you can see it in this picture:
so how do I access this ID? I want to use an SQL command like this:
SELECT * from table_name WHERE ID = 1;
If any order of rows is ok for you, just add a row number according to the current arbitrary sort order:
CREATE SEQUENCE tbl_tbl_id_seq;
ALTER TABLE tbl ADD COLUMN tbl_id integer DEFAULT nextval('tbl_tbl_id_seq');
The new default value is filled in automatically in the process. You might want to run VACUUM FULL ANALYZE tbl to remove bloat and update statistics for the query planner afterwards. And possibly make the column your new PRIMARY KEY ...
To make it a fully fledged serial column:
ALTER SEQUENCE tbl_tbl_id_seq OWNED BY tbl.tbl_id;
See:
Creating a PostgreSQL sequence to a field (which is not the ID of the record)
What you see are just row numbers that pgAdmin displays, they are not really stored in the database.
If you want an artificial numeric primary key for the table, you'll have to create it explicitly.
For example:
CREATE TABLE mydata (
id integer GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
obec text NOT NULL,
datum timestamp with time zone NOT NULL,
...
);
Then to copy the data from a CSV file, you would run
COPY mydata (obec, datum, ...) FROM '/path/to/csvfile' (FORMAT 'csv');
Then the id column is automatically filled.

Is there a way to change the datatype for a column without changing the order of the column?

I have a column where I want to change the data type. I currently am using Redshift. I know I can use the alter table statement to change the datatype, but this would change the order of the columns.
Is there a way to change the datatype without changing the order of the column?
I would recommend creating a new table with the schema you want and copying it over from the old table using a insert into new_table (select * from old_table) statement (here you can also do any casting to the new data type), after which you can drop the old table and rename the new one:
drop table old_table;
alter table new_table rename to old_table;
Using ALTER TABLE table_name ALTER COLUMN column_name TYPE new_data_type will not change the order of the columns in your table.
Please note that this clause can only changes the size of a column defined as a VARCHAR data type.
There are also other limitations described in AWS documentation of ALTER TABLE

Add column to show a row number in the PostgreSQL [duplicate]

I have a table with existing data. Is there a way to add a primary key without deleting and re-creating the table?
(Updated - Thanks to the people who commented)
Modern Versions of PostgreSQL
Suppose you have a table named test1, to which you want to add an auto-incrementing, primary-key id (surrogate) column. The following command should be sufficient in recent versions of PostgreSQL:
ALTER TABLE test1 ADD COLUMN id SERIAL PRIMARY KEY;
Older Versions of PostgreSQL
In old versions of PostgreSQL (prior to 8.x?) you had to do all the dirty work. The following sequence of commands should do the trick:
ALTER TABLE test1 ADD COLUMN id INTEGER;
CREATE SEQUENCE test_id_seq OWNED BY test1.id;
ALTER TABLE test1 ALTER COLUMN id SET DEFAULT nextval('test_id_seq');
UPDATE test1 SET id = nextval('test_id_seq');
Again, in recent versions of Postgres this is roughly equivalent to the single command above.
ALTER TABLE test1 ADD COLUMN id SERIAL PRIMARY KEY;
This is all you need to:
Add the id column
Populate it with a sequence from 1 to count(*).
Set it as primary key / not null.
Credit is given to #resnyanskiy who gave this answer in a comment.
To use an identity column in v10,
ALTER TABLE test
ADD COLUMN id { int | bigint | smallint}
GENERATED { BY DEFAULT | ALWAYS } AS IDENTITY PRIMARY KEY;
For an explanation of identity columns, see https://blog.2ndquadrant.com/postgresql-10-identity-columns/.
For the difference between GENERATED BY DEFAULT and GENERATED ALWAYS, see https://www.cybertec-postgresql.com/en/sequences-gains-and-pitfalls/.
For altering the sequence, see https://popsql.io/learn-sql/postgresql/how-to-alter-sequence-in-postgresql/.
I landed here because I was looking for something like that too. In my case, I was copying the data from a set of staging tables with many columns into one table while also assigning row ids to the target table. Here is a variant of the above approaches that I used.
I added the serial column at the end of my target table. That way I don't have to have a placeholder for it in the Insert statement. Then a simple select * into the target table auto populated this column. Here are the two SQL statements that I used on PostgreSQL 9.6.4.
ALTER TABLE target ADD COLUMN some_column SERIAL;
INSERT INTO target SELECT * from source;
ALTER TABLE test1 ADD id int8 NOT NULL GENERATED ALWAYS AS IDENTITY;

How to add a new identity column to a table in SQL Server?

I am using SQL Server 2008 Enterprise. I want to add an identity column (as unique clustered index and primary key) to an existing table. Integer based auto-increasing by 1 identity column is ok. Any solutions?
BTW: my most confusion is for existing rows, how to automatically fill-in new identity column data?
thanks in advance,
George
you can use -
alter table <mytable> add ident INT IDENTITY
This adds ident column to your table and adds data starting from 1 and incrementing by 1.
To add clustered index -
CREATE CLUSTERED INDEX <indexName> on <mytable>(ident)
have 1 approach in mind, but not sure whether it is feasible at your end or not. But let me assure you, this is a very effective approach. You can create a table having an identity column and insert your entire data in that table. And from there on handling any duplicate data is a child's play. There are two ways of adding an identity column to a table with existing data:
Create a new table with identity, copy data to this new table then drop the existing table followed by renaming the temp table.
Create a new column with identity & drop the existing column
For reference the I have found 2 articles : http://blog.sqlauthority.com/2009/05/03/sql-server-add-or-remove-identity-property-on-column/
http://cavemansblog.wordpress.com/2009/04/02/sql-how-to-add-an-identity-column-to-a-table-with-data/
Not always you have permissions for DBCC commands.
Solution #2:
create table #tempTable1 (Column1 int)
declare #new_seed varchar(20) = CAST((select max(ID) from SomeOtherTable) as varchar(20))
exec (N'alter table #tempTable1 add ID int IDENTITY('+#new_seed+', 1)')