Why does psql not recognise my single quotes? - postgresql

$ psql -E --host=xxx --port=yyy --username=chi --dbname=C_DB -c 'DELETE FROM "Stock_Profile" WHERE "Symbol" = 'MSFT'; '
ERROR: column "msft" does not exist
LINE 1: DELETE FROM "Stock_Profile" WHERE "Symbol" = MSFT;
How do I show psql that MSFT is a string?
It does not like 'MSFT', \'MSFT\' or ''MSFT''

The problem you have is that you've run out of types of quote mark to nest; breaking apart, we have:
your shell needs to pass a single string to the psql command; this can be either single quotes or double quotes
your table name is mixed case so needs to be double quoted
your string needs to be single quoted
In the example you give:
psql -E --host=xxx --port=yyy --username=chi --dbname=C_DB -c 'DELETE FROM "Stock_Profile" WHERE "Symbol" = 'MSFT'; '
The shell sees two single-quoted strings:
'DELETE FROM "Stock_Profile" WHERE "Symbol" = '
`'; '
So the problem is not in psql, but in the shell itself.
Depending on what shell you are using, single-quoted strings probably don't accept any escapes (so \' doesn't help) but double-quoted strings probably do. You could therefore try using double-quotes on the outer query, and escaping them around the table name:
psql -E --host=xxx --port=yyy --username=chi --dbname=C_DB -c "DELETE FROM \"Stock_Profile\" WHERE \"Symbol\" = 'MSFT'; "
Now the \" won't end the string, so the shell will see this as a single string:
"DELETE FROM \"Stock_Profile\" WHERE \"Symbol\" = 'MSFT'; "
and pass it into psql with the escapes processed, resulting in the desired SQL:
DELETE FROM "Stock_Profile" WHERE "Symbol" = 'MSFT';

It's because the single quote before MSFT terminates the string as far as psql is concerned.
As #imsop points out case sensitivity is not preserved when removing double quotes from table names and column names so you can escape the double quotes with backward slash (\) when this is required.
psql -E --host=xxx --port=yyy --username=chi --dbname=C_DB -c "DELETE FROM \"Stock_Profile\" WHERE \"Symbol\" = 'MSFT';"

Related

How to properly insert from stdin in postgresql?

normal insert:
insert into tfreeze(id,s) values(1,'foo');
I tried the following ways, both not working:
copy tfreeze(id,s ) from stdin;
1 foo
\.
copy tfreeze(id,s ) from stdin;
1 'foo'
\.
Only a few questions related from stdin in stackoverflow. https://stackoverflow.com/search?q=Postgres+Insert+statements+from+stdin
--
error code:
ERROR: 22P02: invalid input syntax for type integer: "1 foo"
CONTEXT: COPY tfreeze, line 1, column id: "1 foo"
LOCATION: pg_strtoint32, numutils.c:320
I get code from this(https://postgrespro.ru/education/books/internals) book.
code source: https://prnt.sc/eEsRZ5AK-tjQ
So far I tried:
1, foo, 1\t'foo', 1\tfoo
First, you have to use psql for that (you are already doing that).
You get that error because you use the default text format, which requires that the values are separated by tabulator characters (ASCII 9).
I recommend that you use the CSV format and separate the values with commas:
COPY tfreeze (id, s) FROM STDIN (FORMAT 'csv', FREEZE);
1,foo
\.

How to insert string start with `'` to postgresql when `psql` in bash?

#!/bin/bash
set -e
res_dir='/home/me'
db_port='5432'
db_name='test'
db_user='postgres'
db_password='passwoed'
table_name='record'
#input something start with \ will get error
read -p 'input site: ' site_input
res="'string";
psql postgresql://"$db_user":"$db_password"#localhost:"$db_port"/"$db_name" << EOF
INSERT INTO "$table_name" (site,res) VALUES ($site_input,$res);
EOF
Above script will get error when your input string start with '.
input site: 'jh
ERROR: syntax error at or near "string"
LINE 1: INSERT INTO "record" (site,res) VALUES ('jh,'string);
^
I also tried other methods as below,but none workable.
psql postgresql://"$db_user":"$db_password"#localhost:"$db_port"/"$db_name" << EOF
INSERT INTO "$table_name" (site,res) VALUES ('|| $site_input || ','|| $res || ');
EOF
psql postgresql://"$db_user":"$db_password"#localhost:"$db_port"/"$db_name" << EOF
INSERT INTO "$table_name" (site,res) VALUES (quote_literal($site_input),quote_literal($res));
EOF
How to insert string start with ' to postgresql when psql in bash?
You can escape single quotes by doubling them :
#!/bin/bash
set -e
res_dir='/home/me'
db_port='5432'
db_name='test'
db_user='postgres'
db_password='passwoed'
table_name='record'
#input something start with \ will get error
read -p 'input site: ' site_input
res="'string";
######## Doubling single quotes
site_input="${site_input//\'/\'\'}"
res="${res//\'/\'\'}"
######## Updated with '$site_input','$res'
psql postgresql://"$db_user":"$db_password"#localhost:"$db_port"/"$db_name" << EOF
INSERT INTO "$table_name" (site,res) VALUES ('$site_input','$res');
EOF
//\'/\'\' replaces all single quote ' by ''
For more information, see Parameter expansion

PSQL (postgres or redshift) stored variable to prompt and write query to dynamic filename

My adhoc workflow has me in the psql client often, so often that I define useful queries or settings changes in my .psqlrc file. I'm sharing the solution to this because there are few examples online and since you can't use newlines in a metacommand the syntax gets ugly and debugging took a long time.
Define a psql meta-command in a variable that prompts for sql file path and writes to a local file with a dynamic filename
prompt for sql file to execute
prompt for output filename prefix
generate a dynamic output filename based on ISO reporting week
Here is a manual example of the steps I want to wrap into a .pqslrc-defined variable:
-- the following at psql prompt =>>
select 'file_prefix' || '_week_'
|| to_char(next_day(current_date - 1 - 7 * 1, 'sat') + 1,'iyyy-iw')
|| '.txt' report_filename;
┌──────────────────────────────┐
│ report_filename │
├──────────────────────────────┤
│ file_prefix_week_2019-07.txt │
└──────────────────────────────┘
\out file_prefix_week_2019-07.txt
\a \pset footer off -- no border or row count to output file
\i 'path/to/sql_file.sql'
-- now I have a text file of the output locally on my machine
\out \a \pset footer on
=>>
-- back to normal terminal output
Here is the working solution that can be issued on the psql command line or appended to a .psqlrc and invoked from the psql prompt with the variable name:
-- newlines are included for readability but:
-- **remove all newlines when pasting to .psqlrc**
\set report '\\echo enter filename prefix:\\\\ \\prompt file_prefix \\\\
\\echo enter sql file path:\\\\ \\prompt sql_file \\\\
select :''file_prefix'' || ''_week_''
|| to_char(next_day(current_date - 1 - 7 * 1, ''sat'') + 1,''iyyy-iw'')
|| ''.txt'' report_filename \\gset \\\\
\\pset footer off \\pset border 0 \\pset expanded off \\pset format unaligned \\\\
\\out :report_filename \\\\
\\i :sql_file \\\\
\\out \\\\
\\pset footer on \\pset border 2 \\pset expanded auto
\\pset format aligned \\pset linestyle unicode'
key points:
Postgres psql documentation current version
when copy/pasting remove all the newlines
the variable string cannot have newlines, just one long string
the string is contained in single quotes '
the symbol \\ separates commands
the symbol \ is escaped by doubling
therefore use \\ for \, \\\\ for \\
single quotes within the string are escaped by doubling
therefore use '' for ' within the string
this counts for :variables that are strings as well
\gset assigns the output of a query to a variable of the column name
the :sql_file can include spaces, the variable gets stored as a text string that \i is able to parse without wrapping as :''sql_file''
relevant components in .psqlrc
-- .psqlrc
-- remove newlines from \set variable strings before pasting
\pset fieldsep '\t'
\set prompt_1 '%R%#> '
\set PROMPT1 :prompt_1
\set prompt_copyout 'copyout : : : copyout\n%R%#> '
-- helper variables
-- usage:
-- :copyout desired_output_filename
\set copyout '\\pset footer off \\pset border 0 \\pset expanded off
\\pset format unaligned \\pset title \\pset null ''''
\\set PROMPT1 :prompt_copyout \\out '
-- usage to return to normal terminal output
-- :copyoff
\set copyoff '\\pset footer on \\pset border 2 \\pset expanded auto
\\pset format aligned \\pset title \\pset null ''[null]''
\\set PROMPT1 :prompt_1 \\pset linestyle unicode \\out \\\\'
reformulated with helper variables
I switch between copying out to local text files and viewing sql output in the terminal screen, so my actual usage includes the following helpers:
-- again remove all newlines before pasting into .psqlrc
\set report '\\echo enter filename prefix:\\\\ \\prompt file_prefix \\\\
\\echo enter sql file path:\\\\ \\prompt sql_file \\\\
select :''file_prefix'' || ''_week_''
|| to_char(next_day(current_date - 1 - 7 * 1, ''sat'') + 1,''iyyy-iw'')
|| ''.txt'' report_filename \\gset \\\\
:copyout :report_filename \\\\
\\i :sql_file \\\\
:copyoff'

How to skip empty line in psql \COPY in PostgreSQL

In PostgreSQL psql, how to make \copy command ignore empty lines in input file?
Here is the code to reproduce it,
create table t1(
n1 int
);
echo "1
2
" > m.csv
psql> \copy t1(n1) FROM 'm.csv' (delimiter E'\t', NULL 'NULL', FORMAT CSV, HEADER false);
ERROR: invalid input syntax for integer: ""
CONTEXT: COPY t1, line 3, column n1: ""
There is an empty line in file m.csv
cat m.csv
1
2
<< empty line
PostgreSQL COPY is very strict, so there is not possibility to start COPY in tolerant mode. If it is possible, you can use COPY FROM PROGRAM
[pavel#nemesis ~]$ cat ~/data.csv
10,20,30
40,50,60
70,80,90
psql -c "\copy f from program ' sed ''/^\s*$/d'' ~/data.csv ' csv" postgres

How to ignore escape character ?

this is my string
$mystring = "INSERT INTO `glpi_networkports` (`entities_id`,`is_recursive`,`items_id`,`itemtype`,`comment`,`logical_number`,`name`,`networkinterfaces_id`,`ip`,`mac`,`netmask`,`gateway`,`subnet`,`netpoints_id`)"
How can i ignore escape ?
Because it gave me string like this :
INSERT INTO glpi_networkports (entities_id,is_recursive,items_id,itemtype,comment,logical_number,
ame,
etworkinterfaces_id,ip,mac,
etmask,gateway,subnet,
etpoints_id)
Thanks
Currently your select statement is changed because you used a double quoted string and `n is expanded to a new line, turning the select to an invalid statement.
Use single quotes to maintain the backticks and disable string expansion.
use quote or double the escape char:
$mystring = "INSERT INTO 'glpi_networkports' ..."
$mystring = "INSERT INTO ``glpi_networkports`` ...