Firebird with .net driver - drop table if exists - sql

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.

Related

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

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.

Executing DDL in compound SQL using DashDB (DB2)

I need to execute a DDL command (CREATE TABLE) with other SQL commands. See the code snippet below:
CREATE TABLE test AS
(
SELECT duration AS NUM1
FROM event
WHERE duration IS NOT NULL
) WITH NO DATA;
INSERT INTO test (
SELECT duration AS NUM1
FROM event
WHERE event_duration_tech IS NOT NULL
);
I am creating a table, then populating it.
If I send this code via JDBC, it does not work due to a statement terminator (;) error.
If I wrap it with BEGIN and END to create a compound SQL block, it does not work because DB2 does not allow DDL commands on compound SQL blocks.
The thing is, I need to execute both commands in one shot. Any ideas?
You need to use dynamic SQL to execute some DDL statements:
EXECUTE IMMEDIATE 'CREATE TABLE test AS (SELECT...'

Informix SQL - What is wrong with this simple stored procedure &| trigger syntax?

IBM Informix Dynamic Server Version 11.50.FC6
I am trying to execute a simple stored procedure from within an update trigger. Together, they are used to update a field with the current timestamp when another field in the same row is updated.
Table sp_test:
id (serial int, unique, not null, primary key)
stat (char(1), not null, default="A")
add_date (date, not null, default today)
upd_date (date, null)
The stored procedure code is:
create procedure upd_row_date_proc (cid int)
update sproc_trig_rec set upd_date = current where id = cid;
end procedure;
This executes fine and creates the routine, but the trigger I am trying to implement on updates is not working.
The trigger code is:
create trigger upd_row_date_trig
update of stat on sproc_trig_rec
after (execute procedure upd_row_date_proc(id));
I've tried a bunch of syntax variations, but cannot get it to work.
I usually get my error on the ( char of the 3rd line. Here's the error code:
201: A syntax error has occurred.
Error in line 3
Near character position 0
Does anyone know what I'm doing wrong in the syntax of the trigger? Could this type of updating be defined in the creation of the table, or do I need to accomplish it by doing it the way described above?
Thanks for any help
This finally worked for me
create trigger ken_trig
update of stat on sproc_trig_rec
referencing old as ken_pre_upd
for each row (execute procedure ken_proc(ken_pre_upd.id));

Why does this SQL stored procedure require that a temp table be created for it to work (return results)?

IBM Informix Dynamic Server Version 11.50.FC6
I was working on a small stored procedure that would take name fields from a table and parse them into "user names" with a maximum of 8 chars.
This is the code I was trying:
CREATE PROCEDURE build_jics_user (pid INT)
RETURNING CHAR(8) AS username;
SELECT LOWER((SUBSTR(firstname,0,1))||(SUBSTR(lastname,0,7))) username
FROM id_rec
WHERE id = pid;
END PROCEDURE;
The error returned when executed is:
659: INTO TEMP table required for SELECT statement.
Error in line 5
Near character position 15
I don't understand what the point of summoning a temporary table is, and I also couldn't find any similarly simple examples online that would work without error.
Does anyone know what I'm missing?
What you want to say is this:
CREATE PROCEDURE build_jics_user (pid INT)
RETURNING CHAR(8);
DEFINE username CHAR(8);
SELECT LOWER((SUBSTR(firstname,0,1))||(SUBSTR(lastname,0,7))) INTO username
FROM id_rec
WHERE id = pid;
RETURN username;
END PROCEDURE;
... and execute it like this:
EXECUTE PROCEDURE build_jics_user(42);
UPDATE
If the purpose of this is to be a function, where it's required inside some other SQL, then you might do the following:
CREATE FUNCTION jics_user(fname VARCHAR(255), lname VARCHAR(255))
RETURNING CHAR(8);
RETURN LOWER(SUBSTR(fname,0,1) || SUBSTR(lname,0,7));
END FUNCTION;
... and execute it like this:
SELECT id, firstname, lastname, jics_user(firstname, lastname) AS jics_user, ...
FROM id_rec;
There's no real technical difference between a PROCEDURE and a FUNCTION, it's more an assertion as to how it's used.
This seems to be per design (which must be accounting for the absence of the 'similarly simple examples online'). Apparently, whatever data you are pulling with a SELECT statement in a stored procedure, you cannot return them directly. You should store them either in a temporary table or in variables for later use.
It is likely that your SELECT statement should look like this
SELECT LOWER((SUBSTR(firstname,0,1))||(SUBSTR(lastname,0,7))) INTO username
FROM id_rec
WHERE id = pid;

Why does Microsoft SQL Server check columns but not tables in stored procs?

Microsoft SQL Server seems to check column name validity, but not table name validity when defining stored procedures. If it detects that a referenced table name exists currently, it validates the column names in a statement against the columns in that table. So, for example, this will run OK:
CREATE PROCEDURE [dbo].[MyProcedure]
AS
BEGIN
SELECT
Col1, Col2, Col3
FROM
NonExistentTable
END
GO
... as will this:
CREATE PROCEDURE [dbo].[MyProcedure]
AS
BEGIN
SELECT
ExistentCol1, ExistentCol2, ExistentCol3
FROM
ExistentTable
END
GO
... but this fails, with 'Invalid column name':
CREATE PROCEDURE [dbo].[MyProcedure]
AS
BEGIN
SELECT
NonExistentCol1, NonExistentCol2, NonExistentCol3
FROM
ExistentTable
END
GO
Why does SQL Server check columns, but not tables, for existence? Surely it's inconsistent; it should do both, or neither. It's useful for us to be able to define SPs which may refer to tables AND/OR columns which don't exist in the schema yet, so is there a way to turn off SQL Server's checking of column existence in tables which currently exist?
This is called deferred name resolution.
There is no way of turning it off. You can use dynamic SQL or (a nasty hack!) add a reference to a non existent table so that compilation of that statement is deferred.
CREATE PROCEDURE [dbo].[MyProcedure]
AS
BEGIN
CREATE TABLE #Dummy (c int)
SELECT
NonExistantCol1, NonExistantCol2, NonExistantCol3
FROM
ExistantTable
WHERE NOT EXISTS(SELECT * FROM #Dummy)
DROP TABLE #Dummy
END
GO
This article in MSDN should answer your question.
From the article:
When a stored procedure is executed for the first time, the query
processor reads the text of the stored procedure from the
sys.sql_modules catalog view and checks that the names of the objects
used by the procedure are present. This process is called deferred
name resolution because table objects referenced by the stored
procedure need not exist when the stored procedure is created, but
only when it is executed.