Behaviour of NOT LIKE with NULL values - sql

I want to fetch all columns of a table except of columns of type serial. The closest query to this problem I was able to come up with this one:
SELECT column_name FROM information_schema.columns
WHERE table_name = 'table1' AND column_default NOT LIKE 'nextval%'
But the problem is its also excluding/filtering rows having empty values for column_default.I don't know why the behaviour of Postgres is like this. So I had to change my query to something like this:
SELECT column_name FROM information_schema.columns
WHERE table_name = 'table1'
AND ( column_default IS NULL OR column_default NOT LIKE 'nextval%')
Any better suggestions or rationale behind this are welcome.

About null
'anything' NOT LIKE null yields null, not true.
And only true qualifies for filter expressions in a WHERE clause.
Most functions return null on null input (there are exceptions). That's the nature of null in any proper RDBMS.
If you desire a single expression, you could use:
AND (column_default LIKE 'nextval%') IS NOT TRUE;
That's hardly shorter or faster, though. Details in the manual.
Proper query
Your query is still unreliable. A table name alone is not unique in a Postgres database, you need to specify the schema name in addition or rely on the current search_path to find the first match in it:
Related:
How does the search_path influence identifier resolution and the "current schema"
SELECT column_name
FROM information_schema.columns
WHERE table_name = 'hstore1'
AND table_schema = 'public' -- your schema!
AND (column_default IS NULL
OR column_default NOT LIKE 'nextval%');
Better, but still not bullet-proof. A column default starting with 'nextval' does not make a serial, yet. See:
Auto increment table column
To be sure, check whether the sequence in use is "owned" by the column with pg_get_serial_sequence(table_name, column_name).
I rarely use the information schema myself. Those slow, bloated views guarantee portability across major versions - and aim at portability to other standard-compliant RDBMS. But too much is incompatible anyway. Oracle does not even implement the information schema (as of 2015).
Also, useful Postgres-specific columns are missing in the information schema. For this case I might query the the system catalogs like this:
SELECT *
FROM pg_catalog.pg_attribute a
WHERE attrelid = 'table1'::regclass
AND NOT attisdropped -- no dropped (dead) columns
AND attnum > 0 -- no system columns
AND NOT EXISTS (
SELECT FROM pg_catalog.pg_attrdef d
WHERE (d.adrelid, d.adnum) = (a.attrelid, a.attnum)
AND d.adsrc LIKE 'nextval%'
AND pg_get_serial_sequence(a.attrelid::regclass::text, a.attname) <> ''
);
Faster and more reliable, but less portable.
The manual:
The catalog pg_attrdef stores column default values. The main
information about columns is stored in pg_attribute (see below). Only
columns that explicitly specify a default value (when the table is
created or the column is added) will have an entry here.
'table1'::regclass uses the search_path to resolve the name, which avoids ambiguity. You can schema-qualify the name to overrule: 'myschema.table1'::regclass.
Related:
Find the referenced table name using table, field and schema name
Get the default values of table columns in Postgres?

I think you can use :
SELECT column_name *FROM* information_schema.columns
WHERE table_name = 'table1'
AND ( nvl(column_default,0) *NOT LIKE* 'nextval%');

Related

how to update a column with the default value set during creation in postgres? [duplicate]

I'm looking for a way to run a query to find the default values of the columns of a table in Postgres. For example, if I made a table with the following query:
**Editor's note: I fixed the table definition as it has no impact on the question.
CREATE TABLE mytable (
integer int DEFAULT 2,
text varchar(64) DEFAULT 'I am default',
moretext varchar(64) DEFAULT 'I am also default',
unimportant int
);
I need a query that would tell me, in some format, that the default for integer is 2, text is 'I am default', and moretext is 'I am also default'. The query result can include any value for any other column that doesn't have a default, i.e., unimportant is unimportant for my purposes and doesn't matter at all.
Use the information schema:
SELECT column_name, column_default
FROM information_schema.columns
WHERE (table_schema, table_name) = ('public', 'mytable')
ORDER BY ordinal_position;
column_name │ column_default
─────────────┼────────────────────────────────────────
integer │ 2
text │ 'I am default'::character varying
moretext │ 'I am also default'::character varying
unimportant │
(4 rows)
Up to the schema naming, this should work in any SQL database system.
System catalogs are the source of truth in Postgres:
SELECT pg_get_expr(d.adbin, d.adrelid) AS default_value
FROM pg_catalog.pg_attribute a
LEFT JOIN pg_catalog.pg_attrdef d ON (a.attrelid, a.attnum) = (d.adrelid, d.adnum)
WHERE NOT a.attisdropped -- no dropped (dead) columns
AND a.attnum > 0 -- no system columns
AND a.attrelid = 'myschema.mytable'::regclass
AND a.attname = 'mycolumn';
Related answer on dba.SE discussing information schema vs. system catalogs
LEFT JOIN guarantees a result as long as the column exists. If there is no default you get NULL - which happens to be the default default. And almost always correct. But see:
How to use default value of data type as column default?
To exclude columns without default, use JOIN instead and be prepared to get no row occasionally.
The special cast ::regclass considers the current setting for search_path. With names that aren't schema-qualified (which you should, to be sure!), you may or may not get the expected result. See rebuttal below. More in the manual. Related:
How does the search_path influence identifier resolution and the "current schema"
No need to include pg_class once we have the OID of the table. Faster without.
Why the first answer wouldn't do
#Zohaib's query is almost but not quite right. There are a couple of issues. I copied it here for future reference. Do not use this:
SELECT adsrc as default_value
FROM pg_attrdef pad, pg_atttribute pat, pg_class pc
WHERE pc.relname='your_table_name'
AND pc.oid=pat.attrelid AND pat.attname='your_column_name'
AND pat.attrelid=pad.adrelid AND pat.attnum=pad.adnum
Copied from some blog. Good that it's mentioned, but the source should be added. People reading that blog need to be warned.
Typo in pg_atttribute - fixed easily.
Doesn't return any rows, if there is no default specified for the requested column. Better make that a LEFT JOIN pg_attrdef ON .., so you always get a resulting row if the column exists. It will be NULL, if there is no default, which is actually the correct result because NULL is the default then.
If you remove attname from the WHERE clause, you only get values for columns that actually have a default value. Not for others. And you need to add attname to the SELECT list or you will not know for which column.
The query would also return the default of a column that is already dropped, which is wrong. Read about the details in the manual.
Most importantly: the query can give completely wrong results, as it does not take the schema name into account. There can be any number of table1.col1 in a postgres database: in various schemas. If more than one have a default, you get multiple values. If the column you have in mind does not have a default, but another one in another schema does, you will be fooled and never know it.
Last not least: in recent PostgreSQL releases, the adsrc column has been removed from pg_attrdef by commit fe5038236c, as it was redundant, deprecated and unused in PostgreSQL.
To sum it up: C/P from some blog without insight went dangerously wrong.
I liked Erwin's Answer but was having some difficulties:
Sometimes I would get column names "........pg.dropped.30.......", etc. even with the NOT a.attisdropped qualification. It was not consistent, I wound up having to loop through the results and check the column names.
The returned default value sometimes had a cast attached, e.g. 'I am default'::character varying which did not work when they are being stuffed into web form input values. I could not think of a good way to remove the cast suffix without doing something like .replace(/::.*/, '') which is not robust enough. I bet Erwin can figure out some magical way to EVAL() the returned value and use the a.atttypid column to get the right data type.
So I went back to what I was doing before:
BEGIN;
INSERT INTO mytable DEFAULT VALUES RETURNING *;
ROLLBACK;
One thing to note here is that any SERIAL columns will get incremented. It likely does not matter so long as it is unique if it is just a table index. Otherwise it is a deal breaker.
The other thing to watch out for is any TRIGGER AFTER/BEFORE INSERT which will fire even though the INSERT gets rolled back (I think any changes the trigger function makes will get rolled back though.)
I'm spending some time trying to get to grips with the pg_catalog tables. I'm assuming the names and such come back from the days when letters had to be carved individually and were, consequently, very expensive ;-) Anyway, that's all a fact of life. I wanted to get the default value for a column and ran into this thread. I saw a mention of wanting to have Erwin Brandstetter's code as a function. I've wrapped it up and figured I'd add it to the archives:
CREATE OR REPLACE FUNCTION data.column_default (qualified_name text, column_name text)
RETURNS text
AS $$
SELECT d.adsrc AS default_value -- A human-readable representation of the default value, already typed as text.
FROM pg_catalog.pg_attribute a
LEFT JOIN pg_catalog.pg_attrdef d ON (a.attrelid, a.attnum)
= (d.adrelid, d.adnum)
WHERE NOT a.attisdropped -- no dropped (dead) columns
AND a.attnum > 0 -- no system columns
AND a.attrelid = qualified_name::regclass
AND a.attname = column_name;
$$ LANGUAGE sql;
ALTER FUNCTION data.column_default (qualified_name text, column_name text) OWNER TO user_bender;
I'm using the code (probably in an inhumane manner) like so:
select pg_class.relnamespace::regnamespace as schema_name,
attrelid::regclass as parent_name,
attname,
format_type(atttypid, atttypmod) as data_type,
column_default(attrelid::regclass::text,attname),
attnum
from pg_attribute
left join pg_class on (pg_class.oid = pg_attribute.attrelid::regclass)
From here I figure I'll write a view, etc., once I know better what I'm really after. For now, I'm using a CTE as a temporary view:
with attributes as
(select pg_class.relnamespace::regnamespace as schema_name,
attrelid::regclass as parent_name,
attname,
format_type(atttypid, atttypmod) as data_type,
column_default(attrelid::regclass::text,attname),
attnum
from pg_attribute
left join pg_class on (pg_class.oid = pg_attribute.attrelid::regclass)
)
select *
from attributes
where parent_name::text = 'sales'
Corrections, improvements, and suggestions all welcome...I'm just getting my feet wet in pg_catalog.
you can just type " \d table_name" command , then It will displays some information about the
table, such as the default value of a column.
--create table
skytf=> CREATE TABLE mytable (
skytf(> a integer DEFAULT 2,
skytf(> b varchar(64) DEFAULT 'I am default',
skytf(> c varchar(64) DEFAULT 'I am also default'
skytf(> );
CREATE TABLE
--show table information
skytf=> \d mytable
Table "skytf.mytable"
Column | Type | Modifiers
--------+-----------------------+------------------------------------------------
a | integer | default 2
b | character varying(64) | default 'I am default'::character varying
c | character varying(64) | default 'I am also default'::character varying
SELECT column_default FROM information_schema.columns WHERE
table_name='your_table_name';
in case:
SELECT column_default FROM information_schema.columns WHERE
table_name='your_table_name' AND schema='whatever_schema';
found the answer here: https://www.postgresql.org/message-id/4558AA88.3070102#brainscraps.com
SELECT adsrc as default_value
FROM pg_attrdef pad, pg_atttribute pat, pg_class pc
WHERE pc.relname='your_table_name'
AND pc.oid=pat.attrelid AND pat.attname='your_column_name'
AND pat.attrelid=pad.adrelid AND pat.attnum=pad.adnum
I found this query for postgresql on one of the blogs. you can try this to check if it works. To get values of all coumns, you can try removing AND pat.attname='your_column_name' from where clause.

How to get datatype and such, for only one column of a table?

I usually have to check datatype a particular tablecolumn via a sql code, for which I use
desc tablename
Some tables I look at have a lot of columns, and I think it would be nice if there's a way to get the description for only a particular column (or columns).
Does anyone know of a way to get that info for only a particular (set of) column(s)?
For example something like the beneath would be nice, and possibly there already is?
desc tablename.column_name
Adding on the answer provided by Radim , You not only need the datatype but also the precision for when it comes to datatypes like varchar2(20).
Select TABLE_NAME,COLUMN_NAME,DATA_PRECISION From ALL_TAB_COLUMNS
Where TABLE_NAME = UPPER('TABLE_NAME') and COLUMN_NAME = UPPER('COLUMN_NAME')
Use ALL_TAB_COLUMNS system catalog views
Select COLUMN_NAME, DATA_TYPE From ALL_TAB_COLUMNS
Where TABLE_NAME = UPPER('TAB NAME') and COLUMN_NAME = UPPER('COL NAME')

How can I concisely display a list of table columns in sorted order in postgres?

I know I can get the list of columns for a table displayed in sorted order by executing this long sql command (in this case from the table 'orders'):
select column_name from information_schema.columns
where table_schema = 'public' and table_name = 'orders'
order by column_name;
How can this be done most concisely? For example, if the built-in \d command accepted a flag, it could be:
\d -s orders
Naturally, this doesn't work, but I'd like something similar to avoid having to type in the entire original query above repeatedly. Maybe defining a function that can be invoked concisely that's parameterized by table name?
The raw query is about as terse as it can be. To minimise the typing effort of using it, create a view (with a short name):
create view cols as
select column_name, table_name tab
from information_schema.columns
where table_schema = 'public'
order by column_name
Then to use it:
select * from cols where tab = 'mytable'
Note how (with postgres) you can define a view with an order (saving you from typing the order by every time).
This may not be what you want, but it is my current solution to the problem. I use the shell:
psql -t db_name -c '\d table_name' | sort
This prints out a sorted list of columns which makes discovering schema easier on that random remote system. With the added benefit of not having to remember any arbitrary sql.

How to select all table names where a 'user_id' column is?

I'd like to select all table names where one of columns has a name user_id.
Is it possible in PostgreSQL?
Try this:
select table_name
from information_schema.columns
where column_name = 'user_id'
It should work OK.
Make sure to include the schema name. Your table name can be ambiguous without it. May even lead to harmful confusion:
SELECT table_schema, table_name
FROM information_schema.columns
WHERE column_name = 'user_id';
The information schema is only good if you need cross-RDBMS portability, which is rarely needed and rarely works. I'd rather query the catalog tables directly. Faster and shorter:
SELECT attrelid::regclass
FROM pg_attribute
WHERE attname = 'user_id';
And be sure that you are connected to the same database.

What's the preferred way to return an empty table in SQL?

I know I can return an empty table using the following query :
select * from tbFoo where 1=2
but that code doesn't look nice to me.
Is there a 'standard' way of doing this?
If you're wondering why I want to do such a strange thing, it's because I can't name the datatables I return from a stored procedure, so I need empty placeholders.
Having just run both:
SELECT TOP 0 * FROM Table
and
SELECT * FROM Table WHERE 1=0
They produce exactly the same execution plan.
Most of the time I see 1=0 but yes thats pretty much the standard approach when you really have to. Although really having to is rare.
What you really need is information_schema, using it will allow you to find out the definition of a table.
You don't mention which database you are using, so here is a link about information_schema Support in MySQL, PostgreSQL (and MSSQL, Oracle, Etc)
An example from the site;
SELECT table_name, column_name, is_nullable, data_type, character_maximum_length
FROM INFORMATION_SCHEMA.Columns
WHERE table_name = 'employees'
In your case, all you need are the column names;
SELECT column_name
FROM INFORMATION_SCHEMA.Columns
WHERE table_name = 'employees'