What is the difference between "psql -c" and "psql -f" when executing multiple queries? - sql

I'm trying to execute two sql commands (create a new schema and table), in a way that would enable a rollback of both commands if the execution fails. The database I'm connecting to is AWS Redshift.
create schema if not exists test_schema;
create table test_schema.test_table as select 1;
Initially I tried to execute these commands programatically with python, using both psycopg2 and pyodbc, and got the following error:
ERROR: schema "test_schema" does not exist
I realised that it fails because the first command isn't being comitted, so to fix that , I tried setting the autocommit mode on, and wrapping the statements with "begin/end" block, which didn't help.
When I used psql CLI and ran the following, everything worked as intended (there was no "schema does not exist" error, and after the rollback, both schema and table were gone):
dev=# begin;
BEGIN
dev=# create schema test_schema;
CREATE SCHEMA
dev=# create table test_schema.test_table as select 1;
SELECT
dev=# rollback;
ROLLBACK
I tried to get the same results by running the following in the command line:
psql -c "begin; create schema test_schema; create table test_schema.test_table as select 1;"
This results in the same error:
ERROR: schema "test_schema" does not exist
However, when I put the above code in a file and ran the same command, this time using -f, it worked:
psql -f create_schema_and_table.sql
My questions are:
What is the difference between executing queries with "psql -c" and "psql -f"?
How can the same result be achieved programatically, with python?
Thanks a lot!

I don't know what you are doing wrong, your "psql -c" command works perfectly fine:
ads#diamond:~$ psql -c "begin; create schema test_schema; create table test_schema.test_table as select 1;" postgres
SELECT 1
psql will send the entire string to the server, and execute it in one single transaction. Your problem is that you start a transaction using "begin", but never commit it. Therefore at the end of the psql run, all your changes are rolled back. The next psql command will not find the schema, nor the table. But as long as everything stays in a single psql call, subsequent queries in the same command can see newly created objects.
Your query string should instead look like:
begin; create schema test_schema; create table test_schema.test_table as select 1; commit;
Or, more easy:
create schema test_schema; create table test_schema.test_table as select 1;
Both will work.

Related

I create some tables in SqlDeveloper but I can not see the data stored in the tables. Why I can't see the data in my tables?

I created a sql script to create and populate tables. The script was run in SqlDeveloper.
When I run the query
Select * from table_name
in Sql Developer it does work and returns the data from the table.
But when I open the Command Prompt and I login and execute the same query I receive the message "no rows selected". I also tried to run
SELECT table_name FROM user_tables;
in command line and it does work, all the tables names are returned.
Sounds like you did not commit the transaction. Issue a
COMMIT;
after your INSERT statements.

How to do multiple commands one execute in the HSQLDB GUI?

I have a number of command that I want to do from the GUI. I want to do many groups of these, but I can't get a single group to work. I presume I need to somehow force commits between them, but I can't figure out how to do that. If I execute each one of these commands by itself in order, everything works as expected.
I'm using the EPSG.dat from GeoTools' EPSG.zip.
unzip EPSG.zip
perl -pi -e 's/readonly=true/readonly=false/' EPSG.properties
java -jar hsqldb-2.4.1.jar
jdbc:hsqldb:file:./EPSG
SET AUTOCOMMIT true; -- Press Execute SQL, but this doesn't seem to help.
CREATE TEXT TABLE EPSG_UNITOFMEASURE_COPY (LIKE EPSG_UNITOFMEASURE);
GRANT all ON EPSG_UNITOFMEASURE_COPY TO public;
SET TABLE EPSG_UNITOFMEASURE_COPY SOURCE 'EPSG_UNITOFMEASURE_COPY.csv;encoding=UTF-8';
INSERT INTO EPSG_UNITOFMEASURE_COPY SELECT * FROM EPSG_UNITOFMEASURE;
SET TABLE EPSG_UNITOFMEASURE_COPY SOURCE OFF;
I then get an error of:
user lacks privilege or object not found: EPSG_UNITOFMEASURE_COPY / Error Code: -5501 / State: 42501
I am pretty sure this is an object not found case.
You cannot execute these commands as one block. When a schema definition statement refers to a schema object, that object must already exist.
Execute the CREATE TEXT TABLE, then you can execute the rest as a block.

dropdb mydb not working in postgres

I am a complete beginner with postgresql. I created a test database called iswdp and now I want to delete it. When I do:
dropdb iswdp
the command returns no output and when I \list the table iswdp is still there.
dropdb iswdp;
returns:
ERROR: syntax error at or near "dropdb"
LINE 1: dropdb iswdp
I used:
SELECT pg_terminate_backend(pg_stat_activity.pid)
FROM pg_stat_activity
WHERE datname = current_database()
AND pid <> pg_backend_pid();
which I found from another stackoverflow post to disconnect from all databases then attempted dropdb iswdp again with the same result.
I'm stuck, can someone help me? I'm doing this on linux mint from the bash terminal.
The command dropdb is a command issued from a shell prompt. From a sql prompt (like psql), you would want to issue a DROP DATABASE command.
I recommend opening psql and issuing DROP DATABASE iswdp;. That should work.
You may get an error that looks like ERROR: cannot drop the currently open database, which will happen if you connect to iswdp and try to drop it. If that happens, try instead to connect to the postgres database, and issue the same DROP DATABASE command. It should work.
dropdb is a commando from shell not from psql program, from psql the commnado is drop database iswp;

Creating table in Firebird script causes "unsuccessful metadata update" with deadlock

I have the following script that I run using "isql -i scriptfile.sql":
CONNECT C:\Databasefile.fdb USER user PASSWORD password;
SET TERM !! ;
EXECUTE BLOCK AS BEGIN
IF (EXISTS(SELECT 1 FROM rdb$relations WHERE rdb$relation_name = 'MYTABLE')) THEN
EXECUTE STATEMENT 'DROP TABLE MYTABLE;';
END!!
SET TERM ; !!
CREATE TABLE MYTABLE
(
MYCOLUMN VARCHAR(14) NOT NULL
);
The very first time I run this (when the table does not already exist) the table is created as expected.
If I run the script again I get the following error:
Statement failed, SQLCODE = -607
unsuccessful metadata update
-STORE RDB$RELATIONS failed
-deadlock
After line 8 in file d:\myscript.sql
When the script exits, MYTABLE has been deleted and can no longer be found in the database.
If I run the script a third time the table is once again created and no errors are thrown.
Why can't the script both delete and then recreate a table?
DDL from PSQL is not allowed, using EXECUTE STATEMENT it is not directly forbidden, and usually possible, but still not wise exactly because of these kinds of problems. I am not exactly sure about the reasons, but part of it have to do with how DDL changes are applied in Firebird; the use of execute statement adds additional locks iirc which conflict with a subsequent DDL for the same table name.
Instead of dropping and creating this way, you should use the DDL statement RECREATE TABLE instead.
Note that the word deadlock in this error is actually a bit of a misnomer (there is no real deadlock).

How to count how many sql statements are there in an SQL file?

So, given an SQL file to be executed in Oracle, we are asked to determine how many blocks are to be executed within the SQL file. For example, there is one block in an SQL file containing the following command,
CREATE TABLE customer (id varchar2(42));
two blocks in the following SQL file,
ALTER TABLE customer ADD name varchar2(42);
ALTER TABLE customer DROP COLUMN id;
and three blocks in the following SQL file
CREATE OR REPLACE PROCEDURE printHelloWorld IS
BEGIN
dbms_output.put_line('Hello World!');
END;
/
INSERT INTO customer VALUES ('ivan');
DROP TABLE customer;
We can't assume anything else about the input, other than the fact it will be executed without any error in Oracle SQLDeveloper.
UPDATE
The purpose of asking the question is to ensure that there would only be one statement, which is to be executed, in the SQL file. I am also open to the answer of this question. It would be even better to be able to create a script to split a multiple-statement SQL file to multiple files.
Not a perfect solution but will work in most cases I think.
First create a duff user with no rights except to create a session.
CREATE USER duff IDENTIFIED BY "password";
GRANT CREATE SESSION TO duff;
Then use this with sqlplus and grep to count the ORA- errors - should be one per statement.
sqlplus duff/password#db < script.sql | grep -c ORA-
If you have ALTER SESSION statements then you need a bit more
sqlplus duff/password#db < script.sql | grep -Ec 'ORA-|Session altered.'
There maybe other exceptions, but I think it gives you a workable solution for little overhead. Be careful that scripts don't switch user - but if you have hard-coded usernames and passwords in your scripts you have other issues.