Unable to use crosstab in Postgres - postgresql

Postgres 9.2.1 on OSX 10.9.2.
If I run the following crosstab example query:
CREATE EXTENSION tablefunc;
CREATE TABLE ct(id SERIAL, rowid TEXT, attribute TEXT, value TEXT);
INSERT INTO ct(rowid, attribute, value) VALUES('test1','att1','val1');
SELECT *
FROM crosstab(
'select rowid, attribute, value
from ct
where attribute = ''att2'' or attribute = ''att3''
order by 1,2')
AS ct(row_name text, category_1 text, category_2 text, category_3 text);
I get: ERROR: extension "tablefunc" already exists
But if I comment out CREATE EXTENSION
I get: ERROR: function crosstab(unknown) does not exist
How can I get out of this vicious circle? Is it a known issue?

You can change the first line into:
CREATE EXTENSION IF NOT EXISTS tablefunc;

the problem in my case was that the 'tablefunc' extension was defined on one specific schema in my DB, and not accessible to all schemas in it.
[edit: as explained above, 'not accessible to all schemas' should read 'cannot be loaded on all schemas']
I learned that:
the Extension can only be loaded into one schema - so load it into 'public'
you have to manually drop the extension from one schema before you can load it in another
you can list the loaded extensions per schema in pqsl using the command: \df *.crosstab
[edit: 4. you can access the extension either by search_path, by loading it on public schema or by explicitly specifying a schema]

There's a misconception in your answer:
and not accessible to all schemas in it.
All schemas inside the same database are accessible to all sessions in that same database, (as long as privileges are given). It's a matter of setting the search_path. Schemas work much like directories / folders in the file system.
Alternatively, you can schema-qualify the function (and even operators) to access it independently of the search_path:
SELECT *
FROM my_extension_schema.crosstab(
$$select rowid, attribute, "value"
from ct
where attribute IN ('att2', 'att3')
order by 1,2$$
,$$VALUES ('att2'), ('att3')$$
) AS ct(row_name text, category_2 text, category_3 text);
More:
How to use % operator from the extension pg_trgm?
Dubious crosstab()
Your query returned attributes 'att2' and 'att3', but the column definition list had three categories (category_1, category_2, category_3) that do not match the query.
I removed category_1 and added the second parameter to crosstab() - the "safe" version. More details here:
PostgreSQL Crosstab Query
Aside:
Don't use value as column name, even if Postgres allows it. It's a reserved word in standard SQL.

Related

Is it mandatory to use "" around the table name performing query on PostgreSQL?

I am not so into PostgreSQL and pgAdmin 4 and I have the following doubt.
Following a screenshot of what I can see in my pgAdmin4:
As you can see it is performing this very simple query:
SELECT * FROM public."Example"
ORDER BY id ASC
The thing that I am not understanding is what is this public name in front of the Example table name. What is it?
I was trying to perform a query in this way but it is not working:
SELECT * FROM Example
ORDER BY id ASC
It give me a syntax error. I often used MySql and in MySql it is working.
I tried to replace the query in this way:
SELECT * FROM "Example"
ORDER BY id ASC
and so it is working. So it means that in PosgreSQL database the "" around the table name are mandatory?
The thing that I am not understanding is what is this public name in front of the Example table name. What is it?
As said in postgres documentation:
"By default tables (and other objects) are automatically put into a schema named "public". Every new database contains such a schema."
So it means that in PosgreSQL database the "" around the table name
are mandatory?
Not really but you need to use it if you are using reserved keywords (such as "user","name"and other)or if your table's name contains uppercase(it's your case) letters. Anyways, in this case if you can it's better change your table's name.
You should change your table name to all alphabet in lowercase then try again with
select * from example

What should be the data type of field 'email' in Postgresql database in pgadmin 4?

You can see that I am getting 'No results found' when searching for varchar.
I need to know the data type that I should select for 'email' in postgresql database.
In the past I used text or varchar or character varying
Apart from using of VARCHAR (as suggested by #Maria), you might get some insight from this link:
https://www.dbrnd.com/2018/04/postgresql-how-to-validate-the-email-address-column/
and from this https://dba.stackexchange.com/questions/68266/what-is-the-best-way-to-store-an-email-address-in-postgresql
if you read some parts of it, they created their own functions or constraints, which would likely help you in understanding PSQL more.
TL/DR, or the links might change in the future (shamelessly taken from one of the links):
CREATE EXTENSION citext;
CREATE DOMAIN domain_email AS citext
CHECK(
VALUE ~ '^\w+#[a-zA-Z_]+?\.[a-zA-Z]{2,3}$'
);
-- for valid samples
SELECT 'some_email#gmail.com'::domain_email;
SELECT 'accountant#dbrnd.org'::domain_email;
-- for an invalid sample
SELECT 'dba#aol.info'::domain_email;
As Neil had pointed out, yeah it's just like using custom TYPES.
CREATE DOMAIN creates a new domain. A domain is essentially a data type with optional constraints (restrictions on the allowed set of values).
source
For those of you unfamiliar with the weird characters used to check the value, it's a regex pattern.
And an example used with a table:
CREATE TABLE sample_table ( id SERIAL PRIMARY KEY, email domain_email );
-- The following is invalid, because ".info" has 4 characters
-- the regex pattern only allows 2-3 characters
INSERT INTO sample_table (email) VALUES ('sample_email#gmail.info');
ERROR: value for domain domain_email violates check constraint "domain_email_check"
-- The following query is valid
INSERT INTO sample_table (email) VALUES ('sample_email#gmail.com');
SELECT * FROM sample_table;
id | email
----+------------------------
1 | sample_email#gmail.com
(1 row)
Thanks Neil for the suggestion.
I recommend you yo use CITEXT type that ignores case in values comparison. It's important for email to prevent duplication like username#example.com and UserName#example.com.
This type is the part of the citext extension that could be activates by the following query:
CREATE EXTENSION citext;

Can the foreign data wrapper fdw_postgres handle the GEOMETRY data type of PostGIS?

I am accessing data from a different DB via fdw_postgres. It works well:
CREATE FOREIGN TABLE fdw_table
(
name TEXT,
area double precision,
use TEXT,
geom GEOMETRY
)
SERVER foreign_db
OPTIONS (schema_name 'schema_A', table_name 'table_B')
However, when I query for the data_type of the fdw_table I get the following result:
name text
area double precision
use text
geom USER-DEFINED
Can fdw_postgres not handle the GEOMETRY data type of PostGIS? What does USER-DEFINED mean in this context?
From the documentation on the data_type column:
Data type of the column, if it is a built-in type, or ARRAY if it is
some array (in that case, see the view element_types), else
USER-DEFINED (in that case, the type is identified in udt_name and
associated columns).
So this is not specific to FDWs; you'd see the same definition for a physical table.
postgres_fdw can handle custom datatypes just fine, but there is currently one caveat: if you query the foreign table with a WHERE condition involving a user-defined type, it will not push this condition to the foreign server.
In other words, if your WHERE clause only references built-in types, e.g.:
SELECT *
FROM fdw_table
WHERE name = $1
... then the WHERE clause will be sent to the foreign server, and only the matching rows will be retrieved. But when a user-defined type is involved, e.g.:
SELECT *
FROM fdw_table
WHERE geom = $1
... then the entire table is retrieved from the foreign server, and the filtering is performed locally.
Postgres 9.6 will resolve this, by allowing you to attach a list of extensions to your foreign server object.
Well, obviously you are going to need any non-standard types defined at both ends. Don't forget the FDW functionality is supposed to support a variety of different database platforms, so there isn't any magic way to import remote operations on a datatype. Actually, given that one end could be running on MS-Windows and the other on ARM-based Linux there's not even a sensible way of doing it just with PostgreSQL.

Double quote in the name of table in select query of PostgreSQL

I am running following simple select query in PostgreSQL:
SELECT * FROM "INFORMATION_SCHEMA.KEY_COLUMN_USAGE"
It gives me following error report:
ERROR: relation "INFORMATION_SCHEMA.KEY_COLUMN_USAGE" does not exist
LINE 1: SELECT * FROM "INFORMATION_SCHEMA.KEY_COLUMN_USAGE"
^
********** Error **********
ERROR: relation "INFORMATION_SCHEMA.KEY_COLUMN_USAGE" does not exist
SQL state: 42P01
Character: 15
But when I am running the following query it runs successfully:
SELECT * FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE
Again when I select from a table created by me the situation is reversed. Following one fails:
SELECT * FROM countryTable
while following one runs successfully.
SELECT * FROM "countryTable"
Why is it happening? What is the problem?
You probably created your table so:
CREATE TABLE "countryTable" (
id SERIAL NOT NULL,
country TEXT NOT NULL,
PRIMARY KEY(id)
);
Which create a tablespace wrapped in "", you shouldn't use double quote in general in postgres for table names or columns, try without double quotes:
CREATE TABLE countryTable (
id SERIAL NOT NULL,
country TEXT NOT NULL,
PRIMARY KEY(id)
);
An then you can use this query you already have SELECT * FROM countryTable
While my personal advice is to use legal, lower-case names exclusively and never use double-quote, it is no problem per se.
When you look at the table definition in psql (\d tbl), or at table names in the system catalog pg_class or column names in pg_attributes or any of the information schema views, you get identifiers in their correct spelling (and with all other oddities that may have been preserved by double-quoting them). You can use quote_ident() to quote such names automatically as needed - it only adds double quotes if necessary.
Postgres itself isn't foolish enough to use CaMeL case names. All objects in the information schema or in the system catalog are lower-cased (the names of the system tables and columns, not the names of user tables they carry as data).
Start at the basics, read the manual about identifiers.

Postgresql: is "public." an standard way to fully qualify table name in Postgresql?

If i don't qualify a "public." on account_category table, out account_category will have a conflict with account_category table name.
Does "public." also works on other rdbms?
CREATE OR REPLACE FUNCTION X_RAIN(x VARCHAR, OUT user_id VARCHAR, out account_category varchar, out depth int) returns setof record
AS
$$
BEGIN
return query
select uar.account_id, c.account_category, c.depth
from account_with_types_chart_of_account uar
inner join public.account_category c using(account_category_id);
END;
$$ LANGUAGE 'plpgsql';
Regarding public in PostgreSQL, public is defined as the default schema name when no schema name is specified. However, this can changed in the postgresql.conf file on the search_path = xxx line. To see what your current default schemas are set to issue the following SQL command:
SHOW_ search_path;
If you want to change your default schema path in your open query session, issue the following SQL command:
SET search_path = new_path;
However, in the example you posted I believe that the naming conflict you are having problems with is not with the schema name but with the function parameter name account_category and the table name account_category. You could rename your parameter name to avoid this conflict. In databases with many schemas, for clarities sake I often explicitly specify public at the start of database object names.
Regarding your second question, I don't think PostgreSQL is unique in its usage of public, but I do know that many other databases do their schemas in a different way.
Public is the default schema name.
For example, in MySQL it doesn't have schema (if I recall). Also, if you use another schema instead of public, your code will break.
http://www.postgresql.org/docs/8.3/interactive/ddl-schemas.html
I'd recommend using another variable name. There's probably another way too.
The conflict happens because you used the same name for your variable and table name.
This is a very bad choice of naming, and can lead to many problems.
For example:
create function x (somename TEXT) returns bool as $$
declare
tempbool int4;
begin
select true INTO tempbool from some_table where somename = somename;
return tempbool;
end;
$$ language plpgsql;
This code basically doesn't make any sense, because parser is not able to tell what "somename = somename" means. Same goes for table names (to some degree).
Generally you want your identifiers (table names, column names, variable names) to be unique.
I prefer to use "in_" prefix for arguments, but your choice of naming schema might be different.