deleting tables from postgresql without raising cross-database references are not implemented: using pandas/psycopg2 - sql

I am trying to drop a table from a database.
As long as name_Table is a structured as
schema.table
it all works nicely. However, I do have one table in public schema.
When I try to delete it as:
public.subname.table
I get this answer:
cross-database references are not implemented: "public.subname.table"
How to drop public.subname.table?
print('Connecting to the PostgreSQL database...')
postgresConnection = psycopg2.connect(
host=XXXXXX,
port=YYYYYYYYY,
database="mydb",
user=os.environ['user'],
password=os.environ['pwd'])
cursor = postgresConnection.cursor()
dropTableStmt = "drop TABLE %s;"%name_Table;
# Create a table in PostgreSQL database
print(dropTableStmt)
cursor.execute(dropTableStmt)
postgresConnection.commit()
cursor.close();
print('Database cursor closed.')
postgresConnection.close()
print('Database connection closed.')

public.subname.table runs afoul of Identifier rules in that '.' is not a valid character. The way around that is to double quote the identifier e.g. "public.subname.table" or use the function quote_ident like quote_ident(public.subname.table). In your case drop TABLE quote_ident(%s).
UPDATE
Previous solution was not. I did not test it and just assumed. A tested solution:
--In psql
create table "public.subname.table"(id int);
select * from "public.subname.table";
id
----
(0 rows)
--In Python
import psycopg2
from psycopg2 import sql
con = psycopg2.connect(dbname="test", host='localhost', user='postgres')
cur = con.cursor()
cur.execute(sql.SQL("DROP table {table}").format(table=sql.Identifier("public.subname.table")))
con.commit()
--psql
select * from "public.subname.table";
ERROR: relation "public.subname.table" does not exist
LINE 1: select * from "public.subname.table";
This makes use of the psycopg2 sql module to properly and safely quote the table name in a query string.

DROP TABLE public."subname.table" does what you want.
sql.Identifier("public", "subname.table") is what you want as psycopg2 identifier.

Related

Firebird with .net driver - drop table if exists

I'm new to Firebird and I'm testing a few things to check out the differences between Fb and SQlite (and the .net driver).
I am trying to do a drop table if exists followed by the creation of a table. In Sqlite I am able to do this by:
command.CommandText = #"DROP TABLE IF EXISTS Persons; CREATE TABLE Persons (
PersonID int,
LastName text,
FirstName text,
Address text,
City text); ";
command.ExecuteNonQuery();
However in Firebird the same query fails. I've read that this is not possible to use IFs directly in Firebird SQL, so I've tried to use:
command.CommandText = #"
EXECUTE BLOCK AS
BEGIN IF EXISTS
(SELECT RDB$RELATION_NAME FROM RDB$RELATIONS WHERE RDB$RELATION_NAME = 'Persons')
THEN DROP TABLE Persons; END CREATE TABLE Persons (
PersonID int,
LastName varchar(255),
FirstName varchar(255),
Address varchar(255),
City varchar(255)
); ";
command.ExecuteNonQuery();
But it fails also with the following error:
Dynamic SQL Error SQL error code = -104 Token unknown - line 1, column
27
Can you please help me on this? I've tried to find more info on the web that could help me, but did not have any luck.
Firebird's SQL syntax doesn't have a drop table if exists, instead use recreate table. recreate table will try to drop the table if it exists before creating it. The syntax of recreate table is - other than recreate instead of create - the same as create table.
Your attempt to use execute block fails for two reasons:
You cannot execute two statements together as a command. If you want to execute a script of multiple statements, you'll need to execute each statement individually or use the FbScript class which will parse the script and execute the individual statements for you.
Even if you execute these statements individually, it will still fail, because PSQL (the stored procedure language used in execute block) does not allow execution of DDL. You can use execute statement to circumvent this limitation, but it is better not to do that. In that way you could also address the previous point by executing both - using execute statement - within the execute block.
Alternatively you could just drop the table unconditionally and catch (and ignore) the resulting exception.

There is already an object named '#DIR_Cat' in the database

In my Stored procedure, I have added a command to create a hash temp table #DIR_CAT. But every time I execute the procedure I get this error:
"There is already an object named '#DIR_Cat' in the database."
Even when I have already created an Exists clause at the start of SP to check and drop the table if it is present. Any help is much appreciated.
The code goes like this.
if exists (select * from dbo.sysobjects where id = object_id(N'#DIR_Cat') )
drop table #DIR_Cat
/* some lines of code*/
CREATE TABLE #DIR_Cat (XMLDta xml)
/* some lines of code*/
INSERT #DIR_Cat exec (#stmt)
/* some lines of code*/
drop table #DIR_Cat
Main issue is you're not fully qualifying your objects. Your temp table lives in tempdb, whereas the system views use whatever database you're currently connected to by default. So essentially you're looking for the temp table, but you're looking in whatever database your currently connected to (which I'm guessing is not tempdb).
I'm assuming you're using SQL Server here, although you did also mention mysql in the tags. If that's what you're using, this code may not apply.
Here's the snippet I use for temp table drop/create
if object_id('tempdb.dbo.#<TableName, sysname, >') is not null drop table #<TableName, sysname, >
create table #<TableName, sysname, >
(
)
Side note, don't use dbo.sysobjects. That's a really old compatibility view. If you want to use objects, use sys.objects instead.
temp table does not exists in local DB sys.objects, it is in tempdb
you need to query tempb.sys.objects
the name of the temp table does not appear exactly as it is in the tempdb.sys.objects.
You can't query it just like
select *
from tempdb.sys.objects
where name = '#DIR_Cat' -- This does not works
you need to use object_id()
select *
from tempdb.sys.objects
where object_id = object_id('tempdb..#DIR_Cat')

Use macro variables in Proc SQL in SAS

Two macro variables are defined for table schema and table name and they are used in the proc sql statement in SAS (postgresql interface to Amazon RedShift), sql statement can't be read correctly.
%let table_schema = 'sales';
%let table_name = 'summary_table';
proc sql;
connect to ODBC(DSN='redshift_db', user=masteruser password='*pwd');
create table column_names as
select * from connection to odbc(
select distinct(column_name) as col_name from information_schema.columns where table_schema = &table_schema and table_name = &table_name;
);
create table dt as
select * from connection to odbc(
select * from &table_schema..&table_name;
);
QUIT;
The first table creation throws an error:
ERROR: CLI describe error: ERROR: column "summary_table" does not exist in columns;
The "summary_table" actually exists.
The second table creation throws an error:
ERROR: CLI describe error: ERROR: syntax error at or near "'sales'"; No query has been executed with that handle
which is invalid either.
Check your syntax.
Look at the ERROR: column "summary_table" does not exist in columns;
What that is saying is that the COLUMN named "summary_table" does not exist on the table named "columns". The where clause is trying to compare 2 columns, not a column and a string.
Write the query without macros and get that to work. Then attempt to put the macros in.
This is a syntax issue with the PostGreSQL ODBC driver, not SAS.
I haven't used the PostGreSQL driver before but I know different DBs handle quotes differently. It may be that PostGreSQL wants double quotes instead of single. If this is the case then I would change your code like so:
%let table_schema = sales;
%let table_name = summary_table;
proc sql;
connect to ODBC(DSN='redshift_db', user=masteruser password='*pwd');
create table column_names as
select * from connection to odbc(
select distinct(column_name) as col_name from information_schema.columns where table_schema = "&table_schema" and table_name = "&table_name";
);
create table dt as
select * from connection to odbc(
select * from &table_schema..&table_name;
);
QUIT;
Note that I've removed the single quotes from the %let statments and added double quotes to the where clause in the first query.
Removing the singles quotes from the macro vars will also fix the syntax error you are experiencing with the second query as you were effectively trying to do the following:
select * from 'sales'.'summary_table';
... which is most likely not correct. Again I haven't used PostGreSQL so I can't say for certain - please correct me if I'm wrong and that is correct syntax for it.
Finally, I'd recommend that when working with macro variables in general, that you don't put single quotes around your strings. ie.
%let table_schema = 'sales'; * AVOID THIS WHEN POSSIBLE;
vs
%let table_schema = sales; * USE THIS APPROACH WHEN POSSIBLE;
Put double quotes around the places where macro vars are used instead and you'll probably find things a little easier. Of course there's always circumstances where you may want quotes in the value of the macro variable, but as a general rule of thumb I avoid doing this whenever possible.

Creating a new table using a synonym in SQL Server

I have a synonym created for this table ParaPITD.dbo.BM_00_PolicyMaster that points to ParaPITDYYYYMM.dbo.BM_00_PolicyMaster
There is no table yet - so it acts as a place holder.
I have a stored procedure that creates a temp table #BM_00_PolicyMaster and now I want to insert or select into the place holder where the synonym points to and create the table in ParaPITDYYYYMM.dbo.BM_00_PolicyMaster
If I run this:
select *
into ParaPITD.dbo.BM_00_PolicyMaster
from #BM_00_PolicyMaster
it creates the table in ParaPITD.dbo.BM_00_PolicyMaster and ignores the synonym
If I run this:
INSERT INTO ParaPITD.dbo.BM_00_PolicyMaster
SELECT *
FROM #BM_00_PolicyMaster
it gives me an invalid object error acting like the table must exist before it will insert.
Appreciate any help - thanks
From the doc (http://technet.microsoft.com/en-us/library/ms187552.aspx):
You cannot reference a synonym in a DDL statement
And any statement that creates a table, including SELECT INTO counts as a DDL statement. (See here: http://social.msdn.microsoft.com/Forums/sqlserver/en-US/1085a84c-faac-4d26-8f35-c64d8b901034/insert-into-is-sentence-dml-or-ddl)

Delete table with empty name in PostgreSQL

I'm trying to remove one of my tables stored in PostgreSQL 8.3.8 32bit.
Strange is that my table doesn't have a name, it's empty. Where I do:
SELECT * FORM pg_catalog.pg_tables;
it says that me tablename name is null.
When I try to delete my table:
DROP TABLE sde. ;
where sde is my schemaname,
error appears, telling me that there is a syntax error.
ERROR: syntax error at or near ";"
LINE 1:drop table sde. ;
Is there any way to delete that table?
I also tried that
DROP TABLE sde.'';
But still error appears.
My table has OID. Is it possible to delete it by OID?
The best solution for me would be renaming that table, that I can save my data from that table.
You cannot create table with empty name:
tgr=# create table "" ();
ERROR: zero-length delimited identifier at or near """"
LINE 1: create table "" ();
However you can create a table with a lot of spaces, including newlines:
create table "
" ();
To work with such table:
Find it in information_schema.tables
Copy/paste table name in some command in double quotes ("")
When the previous fails, you can try to update pg_class directly. If you have table OID, try this:
update pg_class set relname = 'test'::name where oid = <<YourOID>>;