Generate value from columns in Postgres - postgresql

I would like to have a generated column, which value will be the concated string from two other values:
CREATE TABLE public.some_data (
user_name varchar NULL,
domain_name serial NOT NULL,
email GENERATED ALWAYS AS (user_name ||'#'||domain_name) stored
);
But that gives SQL Error [42601]: ERROR: syntax error at or near "ALWAYS"

You need to provide the data type for the column as #Belayer commented.
And then you need to explicitly cast domain_name as text (or some varchar). Otherwise you'll get an error that the expression isn't immutable as #nbk commented. serial is translated to be basically an integer and for whatever reason implicit casts of an integer in concatenations are considered not immutable by the engine. We had that just recently here.
So overall, using the given types for the columns, you want something like:
CREATE TABLE public.some_data
(user_name varchar NULL,
domain_name serial NOT NULL,
email text GENERATED ALWAYS AS (user_name || '#' || domain_name::text) STORED);
But it's a little weird that a domain name is a serial? Shouldn't that be a text or similar? Then you wouldn't need the cast of course.

You need to create an IMMUTABLE function to achieve the generate column, for example:
CREATE OR REPLACE FUNCTION generate_email_concat(varchar,int) returns text as
$$
select $1 ||'#'||$2::text;
$$
LANGUAGE SQL IMMUTABLE ;
CREATE TABLE public.some_data (
user_name varchar NULL,
domain_name serial NOT NULL,
email text GENERATED ALWAYS AS (generate_email_concat(user_name,domain_name)) stored
);
INSERT into some_data(user_name) values ('hello');

You try to concatenate varchar and integer. You have to cast domain_name. This works for me
CREATE TABLE public.some_data (
user_name varchar NULL,
domain_name serial NOT NULL,
email varchar GENERATED ALWAYS AS (CASE WHEN user_name IS NULL THEN 'noname'||'#'||domain_name::text ELSE user_name ||'#'||domain_name::text END) STORED
);

Related

can't import files csv in pgAdmin 4

i will import data csv to postgresql via pgAdmin 4. But, there are problem
ERROR: invalid input syntax for type integer: ""
CONTEXT: COPY films, line 1, column gross: ""
i understand about the error that is line 1 column gross there is null value and in some other columns there are also null values. My questions, how to import file csv but in the that file there is null value. I've been search in google but not found similar my case.
CREATE TABLE public.films
(
id int,
title varchar,
release_year float4,
country varchar,
duration float4,
language varchar,
certification varchar,
gross int,
budget int
);
And i try in this code below, but failed
CREATE TABLE public.films
(
id int,
title varchar,
release_year float4 null,
country varchar null,
duration float4 null,
language varchar null,
certification varchar null,
gross float4 null,
budget float4 null
);
error message in image
I've searched on google and on the stackoverflow forums. I hope that someone will help solve my problem
There is no difference between the two table definitions. A column accepts NULL by default.
The issue is not a NULL value but an empty string:
select ''::integer;
ERROR: invalid input syntax for type integer: ""
LINE 1: select ''::integer;
select null::integer;
int4
------
NULL
Create a staging table that has data type of varchar for the fields that are now integer. Load the data into that table. Then modify the empty string data that will be integer using something like:
update table set gross = nullif(trim(gross), '');
Then move the data to the production table.
This is not a pgAdmin4 issue it is a data issue. Working in psql because it is easier to follow:
CREATE TABLE public.films_text
(
id varchar,
title varchar,
release_year varchar,
country varchar,
duration varchar,
language varchar,
certification varchar,
gross varchar,
budget varchar
);
\copy films_text from '~/Downloads/films.csv' with csv
COPY 4968
CREATE TABLE public.films
(
id int,
title varchar,
release_year float4,
country varchar,
duration float4,
language varchar,
certification varchar,
gross int,
budget int
);
-- Below done because of this value 12215500000 in budget column
alter table films alter COLUMN budget type int8;
INSERT INTO films
SELECT
id::int,
title,
nullif (trim(release_year), '')::real, country, nullif(trim(duration), '')::real,
LANGUAGE,
certification,
nullif (trim(gross), '')::float, nullif(trim(budget), '')::float
FROM
films_text;
INSERT 0 4968
It worked for me:
https://learnsql.com/blog/how-to-import-csv-to-postgresql/
a small workaround but it works
I created a table
I added headers to csv file
Right click on the newly created table-> Import/export data, select csv file to upload, go to tab2 - select Header and it should work

Access database, Sql query , Error "Syntax error in DROP TABLE or DROP INDEX."

This is the query , running this in C#.
n getting above error
"DROP TABLE IF EXISTS `NATIONAL_ID_ISSUANCE_CENTER`;
CREATE TABLE `NATIONAL_ID_ISSUANCE_CENTER` (
`ID` INTEGER NOT NULL AUTO_INCREMENT,
`NAME` VARCHAR(100),
`APPLICATION_ID` INTEGER,
`STATUS` INTEGER,
`CREATED_BY` INTEGER,
`UPDATED_BY` INTEGER,
`CREATED_DATE` DATETIME,
`UPDATED_DATE` DATETIME,
`THIRD_PARTY_ID` INTEGER,
`PROVINCE_ID` INTEGER,
INDEX (`APPLICATION_ID`),
PRIMARY KEY (`ID`),
INDEX (`PROVINCE_ID`),
INDEX (`THIRD_PARTY_ID`)
)"
You can't put an IF statement inside Drop and Create statements. Anytime you want to drop a table that you're not sure exists, use the following:
IF(OBJECT_ID('[Database].[Schema].[TableName]') is not null)
BEGIN
DROP TABLE [Database].[Schema].[TableName];
END;
Please note you should replace [Database], [Schema], and [TableName] with the appropriate database, schema, and table names, respectively.

access postgres field given field name as text string

I have a table in postgres:
create table fubar (
name1 text,
name2 text, ...,
key integer);
I want to write a function which returns field values from fubar given the column names:
function getFubarValues(col_name text, key integer) returns text ...
where getFubarValues returns the value of the specified column in the row identified by key. Seems like this should be easy.
I'm at a loss. Can someone help? Thanks.
Klin's answer is a good (i.e. safe) approach to the question as posed, but it can be simplified:
PostgreSQL's -> operator allows expressions. For example:
CREATE TABLE test (
id SERIAL,
js JSON NOT NULL,
k TEXT NOT NULL
);
INSERT INTO test (js,k) VALUES ('{"abc":"def","ghi":"jkl"}','abc');
SELECT js->k AS value FROM test;
Produces
value
-------
"def"
So we can combine that with row_to_json:
CREATE TABLE test (
id SERIAL,
a TEXT,
b TEXT,
k TEXT NOT NULL
);
INSERT INTO test (a,b,k) VALUES
('foo','bar','a'),
('zip','zag','b');
SELECT row_to_json(test)->k AS value FROM test;
Produces:
value
-------
"foo"
"zag"
Here I'm getting the key from the table itself but of course you could get it from any source / expression. It's just a value. Also note that the result returned is a JSON value type (it doesn't know if it's text, numeric, or boolean). If you want it to be text, just cast it: (row_to_json(test)->k)::TEXT
Now that the question itself is answered, here's why you shouldn't do this, and what you should do instead!
Never trust any data. Even if it already lives inside your database, you shouldn't trust it. The method I've posted here is safe against SQL injection attacks, but an attacker could still set k to 'id' and see a column which was not intended to be visible to them.
A much better approach is to structure your data with this type of query in mind. Postgres has some excellent datatypes for this; HSTORE and JSON/JSONB. Merge your dynamic columns into a single column with one of those types (I'd suggest HSTORE for its simplicity and generally being more complete).
This has several advantages: your schema is well-defined and does not need to change if you add more dynamic columns, you do not need to perform expensive re-casting (i.e. row_to_json), and you are able to take advantage of indexes on your columns (thanks to PostgreSQL's functional indexes).
The equivalent to the code I wrote above would be:
CREATE EXTENSION HSTORE; -- necessary if you're not already using HSTORE
CREATE TABLE test (
id SERIAL,
cols HSTORE NOT NULL,
k TEXT NOT NULL
);
INSERT INTO test (cols,k) VALUES
('a=>"foo",b=>"bar"','a'),
('a=>"zip",b=>"zag"','b');
SELECT cols->k AS value FROM test;
Or, for automatic escaping of your values when inserting, you can use one of:
INSERT INTO test (cols,k) VALUES
(hstore( 'a', 'foo' ) || hstore( 'b', 'bar' ), 'a'),
(hstore( ARRAY['a','b'], ARRAY['zip','zag'] ), 'b');
See http://www.postgresql.org/docs/9.1/static/hstore.html for more details.
You can use dynamic SQL to select a column by name:
create or replace function get_fubar_values (col_name text, row_key integer)
returns setof text language plpgsql as $$begin
return query execute 'select ' || quote_ident(col_name) ||
' from fubar where key = $1' using row_key;
end$$;

insert string into text [] column

I have the following issue.
I will receive input as a text from a webservice to insert into a certain psql table. assume
create table test ( id serial, myvalues text[])
the recieved input will be:
insert into test(myvalues) values ('this,is,an,array');
I want to create a trigger before insert that will be able to convert this string to a text [] and insert it
first Idea that came in my mind was to create a trigger before insert
create function test_convert() returns trigger as $BODY%
BEGIN
new.myvalues = string_to_array(new.myvalues,',')
RETURNS NEW
END; $BODY$ language plpgsql
but this did not work
You can use the string_to_array function to convert your string into an string array within your insert query:
INSERT INTO test ( myvalues )
VALUES ( string_to_array( 'this,is,an,array', ',' ) );
Suppose you receive text in the following format this is an array and you want to convert it to this,is,an,array then you can use string_to_array('this is an array', ' ') and it will be converted. However if you are receiving comma separated then you can just used it.
Creating the Table Schema Like this,
CREATE TABLE expert (
id VARCHAR(32) NOT NULL,
name VARCHAR(36),
twitter_id VARCHAR(40),
coin_supported text[],
start_date TIMESTAMP,
followers BIGINT,
PRIMARY KEY (id)
);
Inserting values like this will help you to insert array,
insert into expert(id, name, twitter_id, coin_supported, start_date, followers) values('9ed1cdf2-564c-423e-b8e2-137eg', 'dev1', 'dev1#twitter', '{"btc","eth"}', current_timestamp, 12);

Notnull and empty string in My SQL

Hy I have problem. I wanna to create table with some atributes, and some of them shoud be specified as NOT NULL.. And here comes the problem. When I insert some data into table, and when I insert '' (empty single string) it input data into table, but I dont want this... How to restrict inserting data from inputing single string or inputing nothing..
here are my table
CREATE TABLE tbl_Film
(
ID INT UNSIGNED PRIMARY KEY,
Naziv VARCHAR(50) NOT NULL,
Zanr VARCHAR(50) NOT NULL,
Opis VARCHAR(150) NULL,
Kolicina INT UNSIGNED NOT NULL
);
INSERT INTO tbl_Film VALUES (1,'','Animirani','Mala ribica',2)
This input blank data into Naziv, and I don't want that.. I need to restrict that..
http://prntscr.com/21gfgd
I dont know if this is possible in SQL, but why dont you exchange the '' in your application into the String NULL?
In SQL, NULL is not the same as '' (with the exception of MS SQL via OleDB AFAIR, in which '' should be stored as NULL).
NULL values represent missing unknown data.
See http://www.w3schools.com/sql/sql_null_values.asp
In regular SQL, you should use a CHECK constraint, e.g.
CREATE TABLE tbl_Film (
ID INT UNSIGNED PRIMARY KEY,
Naziv VARCHAR(50) NOT NULL,
Zanr VARCHAR(50) NOT NULL,
Opis VARCHAR(150) NULL,
Kolicina INT UNSIGNED NOT NULL,
CHECK (Naziv <> '')
);
Sadly, this CHECK constraint is NOT implemented by MySQL:
The CHECK clause is parsed but ignored by all storage engines.
See http://dev.mysql.com/doc/refman/5.7/en/alter-table.html
So the only solution I see, at DB level, is to write a P/SQL trigger...