How should I modify a SQL query for PostgreSQL? - postgresql

I have SQL query, which is working nice on Oracle and MSSQL. Now I'm trying this on PostgreSQL and it gives a strange exception: org.postgresql.util.PSQLException: ERROR: missing FROM-clause entry for table "main"
Here is the query:
SELECT *
FROM "main" main
INNER JOIN "something_link" something_link ON main."id" = something_link."mainid"
INNER JOIN "something" somehting ON something_link."somethingid" = something."id"
INNER JOIN "type" type ON something."typeid" = type."id"
This is quite simple query and I can't see why it is not working on Windows XP SP2, PostgreSQL 8.3?

somehting=>something
postgres=# create database test
postgres-# ;
CREATE DATABASE
postgres=# \c test
You are now connected to database "test".
test=# select version();
version
-----------------------------------------------------------------------------------------------
PostgreSQL 8.3.3 on i486-pc-linux-gnu, compiled by GCC cc (GCC) 4.2.3 (Ubuntu 4.2.3-2ubuntu7)
test=# create table main(id int);
CREATE TABLE
test=# create table something_link(mainid int);
CREATE TABLE
test=# create table something(id int);
CREATE TABLE
test=# create table type(id int);
CREATE TABLE
test=# alter table something add column typeid int;
ALTER TABLE
test=# SELECT *
test-# FROM "main" main
test-# INNER JOIN "something_link" something_link ON main."id" = something_link."mainid"
test-# INNER JOIN "something" somehting ON something_link."somethingid" = something."id"
test-# INNER JOIN "type" type ON something."typeid" = type."id"
test-# ;
ERROR: column something_link.somethingid does not exist
LINE 4: INNER JOIN "something" somehting ON something_link."som...
^
test=# alter table something_link add column somethingid int;
ALTER TABLE
test=# SELECT *
FROM "main" main
INNER JOIN "something_link" something_link ON main."id" = something_link."mainid"
INNER JOIN "something" *somehting* ON something_link."somethingid" = something."id"
INNER JOIN "type" type ON something."typeid" = type."id"
;
ERROR: invalid reference to FROM-clause entry for table "something"
LINE 4: ...hing" somehting ON something_link."somethingid" = something....
^
HINT: Perhaps you meant to reference the table alias "somehting".
test=# SELECT *
FROM "main" main
INNER JOIN "something_link" something_link ON main."id" = something_link."mainid"
INNER JOIN "something" something ON something_link."somethingid" = something."id"
INNER JOIN "type" type ON something."typeid" = type."id"
;
id | mainid | somethingid | id | typeid | id
----+--------+-------------+----+--------+----
(0 rows)

The real problem is actually not the query, but the PostgreSQL 8.3 default configuration.
After correcting the spelling mistake (10x Kendrick Wilson), the problem persisted, until I edited the "postgresql.conf" file. There should be a line:
add_missing_from = on
This line ensures compatibility with the other SQL dialects.

According to this, seems like you either mistyped an alias or used a table name in place of it.

Related

Postgresql : ERROR: in creating temp table with list object values

I am writing a Postgresql function (using pgAdmin GUI) that will be invoked from my Spring Boot application with java list object as parameters
My actual requirement is mentioned here and with the suggestions to create a temp table with list values to optimize query, following is the Postgres function which I have tried by referring from here:
CREATE FUNCTION public."getInventory"("vals1Arg" character varying[], "vals2Arg" character varying[])
RETURNS "INVENTORY"
LANGUAGE 'sql'
AS
$BODY$
// I assume the below two lines create two temp tables and populate the table
with my list object values
CREATE TEMP TABLE t1 AS
SELECT * FROM VALUES(vals1Arg)
CREATE TEMP TABLE t2 AS
SELECT * FROM VALUES(vals2Arg)
SELECT * FROM "INVENTORY"
where "COLUMN_1" in (select * from t1)
and "COLUMN_2" in (Select * from t2);
$BODY$;
Following is the code snippet by how I am invoking postgres function
#Query(nativeQuery = true, value = "select \"getInventory\" (:vals1Arg,:vals2Arg)")
List<Inventory> getInventoryInfo(List<String> vals1Arg, List<String> vals2Arg);
As the list is going to be huge, I am creating a temporary table with values from the list object paramaters and use it in my select query
Thank you in advance !!
There are several problems:
The syntax of the CREATE TABLE ... AS should be
CREATE TABLE ... AS
SELECT * FROM (VALUES (...)) AS alias;
instead of
CREATE TABLE ... AS
SELECT * FROM VALUES (...);
You need these parentheses and the alias.
The subselect in the query won't work, as it compares a varchar (COLUMN_1) with a varchar[] (the column of the temporary table).
To make that work, you'd have to
SELECT * FROM "INVENTORY"
WHERE "COLUMN_1" = ANY (SELECT * FROM t1);
If you want to create temporary tables rather than using the array directly in the SELECT, you had better
CREATE TEMP TABLE t1 AS
SELECT * FROM unnest(vals1Arg) AS u(c);
CREATE TEMP TABLE t2 AS
SELECT * FROM unnest(scomoIdList) AS u(c);
ANALYZE t1, t2;
RETURN QUERY SELECT * FROM "INVENTORY"
JOIN t1 ON "INVENTORY"."COLUMN_1" = t1.c
JOIN t2 ON "INVENTORY"."COLUMN_2" = t2.c;
This assumes that the lists don't contain duplicate entries.

How to make sql query on table name with space separated in Postgres?

I'm using postgres database and it has table with name say 'System Tenant'. Now I want to make query on it, I do -
select * from "System Tenant";
but it results into error -
ERROR: relation "System Tenant" does not exist
LINE 1: select * from "System Tenant"
^
Could you please suggest how I can resolve it?
lets say:
so=# create schema t;
CREATE SCHEMA
so=# create table t."Bad Name"();
CREATE TABLE
so=# create table "b#d Name"();
CREATE TABLE
now find all:
so=# select oid::regclass from pg_class where relname ilike '% name%';
oid
--------------
t."Bad Name"
"b#d Name"
(2 rows)
and use exactly as it is listed:
so=# select * from t."Bad Name";
--
(0 rows)
or
so=# select * from "b#d Name";
--
(0 rows)

Get current table OID (regclass) when inserting in a table

I have a table with a column storing table OID of table where records come from. If this field must be filled (NOT NULL) but can have a default value if not provided. I would like to store the current table OID when inserting.
CREATE TABLE t AS(
Source regclass NOT NULL DEFAULT current_table_name()::regclass
);
Is there any function (current_table_name) in postgreSQL table to perform this task?
There is no such function, but you can achieve the goal in three steps:
Create the table without DEFAULT.
Find the OID of the new table.
ALTER the table and set the DEFAULT.
It is better to use the table OID than to cast the table name to regclass, because with the latter INSERTs will suddenly start failing after the table is renamed.
Here is a DO block that would achieve that:
DO $$DECLARE
reloid oid;
BEGIN
CREATE TABLE t (source regclass NOT NULL);
SELECT t.oid INTO reloid
FROM pg_class t
JOIN pg_namespace n ON t.relnamespace = n.oid
WHERE t.relname = 't' AND n.nspname = current_schema;
EXECUTE 'ALTER TABLE t ALTER source SET DEFAULT ' || reloid;
END;$$;

How does postgres db_link_build_sql_insert work?

I can't seem to figure out how this function is supposed to work for pushing data across from one table in your local database to another on a separate database. I have looked at the documentation and still don't understand the example given. I am working with a postgres 9.2 which makes it possible to use dblink.
Here is some example code where I am creating a test database and pushing values from my local table to the table on the test database. Can someone please fill in the missing part of the dblink_build_sql_insert function?
--drop database if exists testdb;
--create database testdb;
drop table if exists t;
create table t ( a integer, b text);
insert into t values (1,'10'), (2,'10'), (3,'30'), (4,'30');
create extension if not exists dblink;
select dblink_connect('dbname=testdb');
select dblink('drop table if exists t;');
select dblink('create table t ( a integer, b text);');
select dblink_build_sql_insert('t', ????);
select * from dblink('select * from t;') as (a integer, b text);
from docs:
Synopsis
dblink_build_sql_insert(text relname,
int2vector primary_key_attnums,
integer num_primary_key_atts,
text[] src_pk_att_vals_array,
text[] tgt_pk_att_vals_array) returns text
You don't have PK specified, so I assume it is on (a), which automatically means, that primary_key_attnums = 1(PK on first column) and num_primary_key_atts=1 (one column PK). Two rest values made same to prepare statement ro "replicate" row with a=1 as is:
b=# select dblink_build_sql_insert('t',
'1'::int2vector,
1::int2, -- num of pkey values
'{1}'::text[], -- old pkey
'{1}'::text[] -- new pkey
)
;
dblink_build_sql_insert
-------------------------------------
INSERT INTO t(a,b) VALUES('1','10')
(1 row)
b=# select dblink($$INSERT INTO t(a,b) VALUES('1','10')$$);
dblink
----------------
("INSERT 0 1")
(1 row)
b=# select * from dblink('select * from t;') as (a integer, b text);
a | b
---+----
1 | 10
(1 row)
b=# select dblink_disconnect();
dblink_disconnect
-------------------
OK
(1 row)

pg_relation_size tells me column doesn't exist

http://www.postgresql.org/docs/8.4/static/functions-admin.html says:
pg_relation_size
accepts the OID or name of a table, index or toast table, and returns the size in bytes
However when I use it with a valid table name, I get the error:
column [table] does not exist...
I know my table exists, because doing
SELECT count(*) FROM [table]
returns a valid number. Any ideas?
I got the same error though the cause was different. pg_relation_size is case insensitive, so if you have anything other than lower case it will not work out of the box:
postgres=> SELECT pg_size_pretty(pg_total_relation_size('MyTable'));
ERROR: relation "mytable" does not exist
LINE 1: SELECT pg_size_pretty(pg_total_relation_size('mytable...
^
postgres=> SELECT pg_size_pretty(pg_total_relation_size('"MyTable"'));
pg_size_pretty
----------------
225 MB
(1 row)
So in order for this to work in a SELECT statement you need to enclose the table name in quotes:
postgres=> SELECT relname, nspname, pg_size_pretty(pg_relation_size('"' || relname || '"'))
FROM pg_class c LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
WHERE c.relkind IN ('r','') AND n.nspname NOT IN ('pg_catalog', 'pg_toast') AND pg_table_is_visible(c.oid)
ORDER BY c.relpages DESC;
Try explicitely adding the schema (e.g. 'public') where the table is located in the pg_relation_size call.
Like this (untested):
select pg_relation_size(public.mytablename) from pg_tables