I need to create, manage and drop schemas on the fly. If I go to create a schema that already exists, I want to (conditionally, via external means) drop and recreate it as specified. How can I check for the existence of said schema on my Postgres 9 server?
Currently, I'm doing this:
select exists (select * from pg_catalog.pg_namespace where nspname = 'schemaname');
but I feel like there's probably another way... is this the "proper" way to query Postgres for the existence of a particular schema?
The following query will tell you whether a schema exists.
SELECT schema_name FROM information_schema.schemata WHERE schema_name = 'name';
If you are a total purist or you want to gain some milisecs. I recommend you to make use of postgres native system catalog. One can avoid then nested loop which is caused by calling pg_catalog anyway...
SELECT EXISTS(SELECT 1 FROM information_schema.schemata
WHERE schema_name = 'name');
If you querying pg_namespace directly:
SELECT EXISTS(SELECT 1 FROM pg_namespace WHERE nspname = 'name');
Planer's work is much simpler:
So your own solution was the best.
Somewhat related and perhaps of interest to others looking for conditional schema creation. I found myself using code like this in some of my creation scripts:
DO $$
BEGIN
IF NOT EXISTS(
SELECT schema_name
FROM information_schema.schemata
WHERE schema_name = 'pgcrypto'
)
THEN
EXECUTE 'CREATE SCHEMA pgcrypto';
END IF;
END
$$;
This can be one of the approaches. Drop the schema first and then create it.
IF EXISTS:
Do not throw an error if the schema does not exist. A notice is issued in this case.
So,
DROP SCHEMA IF EXISTS schema_Name
Create SCHEMA schema_Name
If you want to create a schema if it doesn't exist you can just execute:
CREATE SCHEMA IF NOT EXISTS foo
Source: https://www.postgresql.org/docs/current/sql-createschema.html
This is valid for the PostgreSQL that will check if the schema if exist and if not then will create it:
CREATE SCHEMA IF NOT EXISTS tenant;
From http://www.postgresql.org/docs/9.1/static/infoschema-schemata.html (emphasis my own):
The view schemata contains all schemas in the current database that are owned by a currently enabled role.
So your original solution/query is more reliable than Peter's, albeit non-standard.
Use
SELECT EXISTS (SELECT 1 FROM pg_catalog.pg_namespace WHERE nspowner <> 1 AND nspname = 'schemaname');
If you check https://www.postgresql.org/docs/current/static/infoschema-schemata.html, you see
The view schemata contains all schemas in the current database that the current user has access to (by way of being the owner or having some privilege).
This means the query in accepted answer using information_schema.schemata doesn't show schemas that the current user isn't the owner of or doesn't have the USAGE privilege on.
SELECT 1
FROM pg_catalog.pg_namespace
WHERE nspowner <> 1 -- ignore tables made by postgres itself
AND nspname = 'schemaname';
is more complete and will show all existing schemas that postgres didn't make itself regardless of whether or not you have access to the schema.
This one worked for me (Postgres 9.3):
Select exists (SELECT 1 FROM information_schema.schemata where catalog_name = 'My_BD_with_UpperCase_characters_in_its_Name')
NONE of those will work if you have objects (tables,sprocs,views) within a particular schema - IT WILL FAIL during DROP...
CREATE & MANAGE is the easy part.. It's the drop that will get you.. Anyways, I couldn't find a suitable answer, so I posted here for others..
SEE LINK HERE: http://social.msdn.microsoft.com/Forums/en-US/transactsql/thread/4753d1b8-f547-44c6-b205-aa2dc22606ba/#6eb8238a-305e-40d5-858e-0fbd70454810
Related
I want to do something like
DROP PROJECTION IF EXISTS myProjection;
Apparently I can use IF EXISTS for a table but not a projection.
I understand if I drop the table with CASCADE, that should drop the corresponding projections, but I apparently have some orphaned projections which I do not have a track of. And sometimes when I rename tables/projections, it fails saying projection already exists.
The Drop Projection page and this stackoverflow page for generic sql do not help much.
Edit: I am using this in Mybatis Migrations. So my entire migration would fail if there is an error in any of the scripts. So, no I can not ignore the error.
If there is no IF EXISTS for a projection -- is there a programatic way (LIKE TSQL/PLSQL) where I could specify a condition to check if the projection exists and take an action whether to drop it or not?
There is no drop projection IF EXISTS .... You can just use drop projection ... and - of course - you will get an error message if the projection you're trying to delete does not exists.
You can list ALL projections for a given schema/table using a SQL like this:
\set schema '''my_schema'''
\set table '''my_table'''
select
projection_name,
sum(row_count) as row_count,
sum(used_bytes) as used_bytes,
sum(wos_row_count) as wos_row_count,
sum(wos_used_bytes) as wos_used_bytes,
sum(ros_row_count) as ros_row_count,
sum(ros_used_bytes) as ros_used_bytes
from
projection_storage
where
anchor_table_schema = :schema and
anchor_table_name = :table
group by 1
order by 1
;
And the following will list all projections associated with tables in a given schema:
\set schema '''my_schema'''
select
projection_name,
anchor_table_name,
sum(row_count) as row_count,
sum(used_bytes) as used_bytes,
sum(wos_row_count) as wos_row_count,
sum(wos_used_bytes) as wos_used_bytes,
sum(ros_row_count) as ros_row_count,
sum(ros_used_bytes) as ros_used_bytes
from
projection_storage
where
anchor_table_schema = :schema
group by 1, 2
order by 1, 2
;
you can query catalog table in vertica, this will give you schema names of all present schemas ,
select v_catalog.columns from v_catalog.columns;
i sometime use this select query , which gives me evey info related to a table
select export_objects('','your_schema.table_name');
This is possible since Vertica 9.2.x.
DROP PROJECTION IF EXISTS myProjection;
Reference: https://www.vertica.com/docs/9.2.x/HTML/Content/Authoring/SQLReferenceManual/Statements/DROPPROJECTION.htm
I am connected to a oracle database with a read only user and i used service name while Setting up connection in sql developer hence i dont know SID ( schema ).
How can i find out schema name which i am connected to ?
I am looking for this because i want to generate ER diagram and in that process at one step it asks to select schema. When i tried to select my user name , i dint get any tables as i guess all tables are mapped with schema user.
Edit: I got my answer partially by the below sql Frank provided in comment , it gave me owner name which is schema in my case. But I am not sure if it is generic solution applicable for all cases.
select owner, table_name from all_tables.
Edit: I think above sql is correct solution in all cases because schema is owner of all db objects. So either i get schema or owner both are same. Earlier my understanding about schema was not correct and i gone through another question and found schema is also a user.
Frank/a_horse_with_no_name Put this in answer so that i can accept it.
Call SYS_CONTEXT to get the current schema. From Ask Tom "How to get current schema:
select sys_context( 'userenv', 'current_schema' ) from dual;
To create a read-only user, you have to setup a different user than the one owning the tables you want to access.
If you just create the user and grant SELECT permission to the read-only user, you'll need to prepend the schema name to each table name. To avoid this, you have basically two options:
Set the current schema in your session:
ALTER SESSION SET CURRENT_SCHEMA=XYZ
Create synonyms for all tables:
CREATE SYNONYM READER_USER.TABLE1 FOR XYZ.TABLE1
So if you haven't been told the name of the owner schema, you basically have three options. The last one should always work:
Query the current schema setting:
SELECT SYS_CONTEXT('USERENV','CURRENT_SCHEMA') FROM DUAL
List your synonyms:
SELECT * FROM ALL_SYNONYMS WHERE OWNER = USER
Investigate all tables (with the exception of the some well-known standard schemas):
SELECT * FROM ALL_TABLES WHERE OWNER NOT IN ('SYS', 'SYSTEM', 'CTXSYS', 'MDSYS');
How about the following 3 statements?
-- change to your schema
ALTER SESSION SET CURRENT_SCHEMA=yourSchemaName;
-- check current schema
SELECT SYS_CONTEXT('USERENV','CURRENT_SCHEMA') FROM DUAL;
-- generate drop table statements
SELECT 'drop table ', table_name, 'cascade constraints;' FROM ALL_TABLES WHERE OWNER = 'yourSchemaName';
COPY the RESULT and PASTE and RUN.
How can I delete the contents of a table only if it exists? Preferably the sql statement should be standard and not oriented to any db.
Please notice that I do not want to drop a table if it exists, i.e.
DROP TABLE IF EXISTS foo
PS: I have already checked truncate and delete but they don't fit the requirement if the table exists.
As far as i know, there is no standard for "if exists". Some databases support it, others do not, and will give you a syntax exception.
Edit
INFORMATION_SCHEMA does not usually change between different versions and is common in most databases, and to my best knowledge this is the most proper way to check whether a table exists in SQL:
IF (EXISTS (SELECT *
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME = tableName ))
BEGIN
DELETE FROM tableName
END
The environment is Oracle 9 & 10. I do not have DBA level access.
The problem is to verify that a specific column exists in a specific table, in another schema.
There are two cases to deal with.
Another schema in the same instance
A schema in a different instance, using a db_link
Given my schema FRED and another schema BARNEY, I tried something like this
SELECT 1
FROM BARNEY.USER_TAB_COLS
WHERE TABLE_NAME = 'SOME_TABLE'
AND COLUMN_NAME = 'SOME_SPECIFIC_COLUMN'
Which yielded [1]: (Error): ORA-00942: table or view does not exist
After vegging on this awhile, I realized that USER_TAB_COLS, is not really a table. It is a view. I have been selecting from tables all along, but not from a view.
I tried the same thing with my db_link, and was surprised to see data come back. A db_link has an embedded schema_name/password in it, so it seems reasonable to me that it worked, as it effectively logs in to the other schema, which should make the views reachable.
Having Googled around, and worn out my eyeballs on on the mountain of Oracle doc,
I am looking for someone to point me in the correct direction, or at least point out what I am missing.
What techniques are available for getting user table related metadata from a schema in the same instance in order to validate that a specific column exists?
Thanks in advance.
Evil.
+1 for good answers.
Thank you.
You can use the following query:
SELECT 1
FROM ALL_TAB_COLS
WHERE TABLE_NAME = 'SOME_TABLE'
AND COLUMN_NAME = 'SOME_SPECIFIC_COLUMN'
AND OWNER = 'BARNEY';
(User_Tables and User_Tab_Cols are just views on all_tables and all_tab_coumns with a where owner = <Current User> attached to it)
If you're allowed to see the Barney's some_table (i.e. you have been GRANTed at least SELECT privileges on it), then you'll know if the column is there. If you have no rights on the table, you won't be able to get meta information on it.
As with the other replies, normally I use ALL_TAB_COLUMNS for a query like this. But that will only show columns in tables where you have SELECT. And it's select on that column -- in the unlikely event that they've implemented column-level privileges for that table, you may be able to see the table, but not see the specific column of interest. For most of us, that's extremely rare.
DBA_TAB_COLUMNS will show all columns, but you'll need select on it granted to your schema by your DBA. (Actually, you'll need a grant on ALL_TAB_COLUMNS to use it, but that's common in most shops). The DBMS_METADATA PL/SQL Built-in package can also be used, with similar limitations, but I think you'll find it more complicated.
Of course, you can also just try to select a record from barney.some_table.some_column#my_dblink (or whatever pieces of that you're interested in). And then handle the exception. Ugly, I wouldn't recommend it in most situations.
You would use all_tab_columns for that.
But beware that you'll only see what you are allowed to see.
Same instance, different schema:
Select Count(*)
From all_tab_cols
Where owner = 'BARNEY' and
table_name = 'SOME_TABLE' and
column_name = 'SOME_SPECIFIC_COLUMN';
The count(*) has the advantage of always returning a single row with a value of either 1 or 0, so you do not have to deal with NO_DATA_FOUND errors in PL/SQL.
Across a DB Link, same schema as the one you connect as:
Select Count(*)
From user_tab_cols#MY_DB_LINK
Where table_name = 'SOME_TABLE' and
column_name = 'SOME_SPECIFIC_COLUMN';
Across a DB Link, different schema than the one you connect as:
Select Count(*)
From all_tab_cols#MY_DB_LINK
Where owner = 'BARNEY' and
table_name = 'SOME_TABLE' and
column_name = 'SOME_SPECIFIC_COLUMN';
Is there a portable way of determining if a database table already exists or not?
Portable? I don't think so.
Maybe the closest you can get is:
select * from <table>
And this would return an error if the table doesn't exist.
This is as portable as it gets, sadly:
select
count(*)
from
information_schema.tables
where
table_name = 'tablename'
and table_schema = 'dbo'
This definitely works on SQL Server, MySQL, and Postgres. Not so much on Oracle, though. You'd have to access the Oracle data dictionary for that. However, there is an open source project that creates information_schema in Oracle from the data dictionary. You can try that if you need absolute portability.
P.S.-Schema doesn't have to be dbo, but that's the most common.
I would say
select 'x' from <table_name> where 0=1;
The drawback is that if you get an error, you don't know for sure what was the real cause. It might be missing table or e.g. a connection error. You can parse the error message, but definitely it would not be portable.
The INFORMATION_SCHEMA views are ANSI standard - so those should be your most portable option. Don't forget to add the schema and table type to your where clause...
if exists(select *
from information_schema.tables
where table_schema = 'dbo'
and table_name = 'MyTable'
and table_type = 'basetable')
begin
-- your code here
end
Here is something that is reasonably portable:
select now() from TABLE limit 1;
It doesn't rely on knowledge of any particular column.
It doesn't incur the overhead that count(*) sometimes has.
It doesn't matter whether the table is empty or not.
It fails if the table doesn't exist.
As every DBMS has its own metabase, I think the most "portable" way to do this is using the application caller itself. Something like
try
execute("select top 1 * from table")
return (true)
catch
return false
Attempt to query the table. If the query fails -- you get an error, it doesn't exist.
That is probably as portable as you can get. The burden of producing the result then depends on the code querying the table/database.
select top 1 *
from MyTable
Keep the query as simple as possible to prevent other possible errors.