PostgreSQL: Conditional where clause using regex not working - postgresql

I am trying to implement conditional where clause that sets id when maybe_numeric is really numeric, but the following does end up with ERROR: invalid input syntax for integer: "xxx" for non-numeric values.
How can I fix the first condition so that the second condition is evaluated only if the maybe_numeric is numeric?
SELECT *
FROM some_table st
WHERE NOT ${maybe_numeric} ~ '^\d+$' OR st.id = ${maybe_numeric}::int

Related

PostgreSQL execute SELECT * FROM (t as a); return ERROR: syntax error at or near ")"

Why these SQLs can't work in PostgreSQL?
SELECT * FROM (t as a);
or
SELECT * FROM (t);
ERROR: syntax error at or near ")"
Those SQLs work well in MySQL.
Well, it's invalid SQL.
If you want to give the table an alias you need to use from t as a.
The form from (....) requires a valid query inside the parentheses and t as a (or just t) is not a valid query. Additionally: a derived table (which is what (...) defines) requires an alias. So at least it has to be from (...) as bla
To get all rows and all columns from a table the SQL standard provides the shortcut table some_table which is supported by Postgres.
So the following would be valid:
select * from (table t) as a
Typically, table alias' are applied where there is a join. For example:
SELECT alias1.login_name, alias2.name
FROM tablename1 AS alias1
JOIN tablename2 AS alias2
ON alias1.id = alias2.role_id;
To apply an alias to a single table:
SELECT * FROM tablename AS alias;
..will do it for you, no need for parentheses.
You can confirm/test by example below if value is an integer:
SELECT * FROM tablename AS alias
WHERE alias.colum = value;
..or if value is a string:
SELECT * FROM tablename AS alias
WHERE alias.colum = 'value';
postgreSQL is strongly-typed, so the first example above will work for Int and Bool values, however if you have Date or other values, you may need to apply type casting. See this link for helpful info*: www.postgresqltutorial.com/postgresql-tutorial/postgresql-cast.
**Remember: For psql strings, always use single quotes for values, use double quotes for table names and column names.

Postgresql pass function parameter with casting

I created two functions. The first function, getProductOrder, is getting token whose type is character varying. The second function is getOrderTechnicalDetails whose function parameter is character varying.
For example When I call getProductOrder with quotation marks that is working nothing problem the function
Worked example
select
(select row_to_json(getOrderTechnicalDetails('991964b80d4f41a416b48ac99bdc07ad')) as techDetails),
o.*
from
(select * from getProductOrder(null, '54e91016-46d0-11e7-912d-001dd8b72237', null, 9181, 1::smallint)) o
But I have to use dynamic parameter here problem is casting problem function can't determine casting.
When I execute this query I get syntax error. How can I solve this problem?
Query
select
(select row_to_json(getOrderTechnicalDetails(o.token::character varying)) as techDetails),
o.*
from
(select * from getProductOrder(null, '54e6341-46d0-11e7-912d-001dd8b72237', null, 9181, 1::smallint)) o
Error
ERROR: invalid input syntax for integer: "-"
SQL state: 22P02
Context: SQL function "getordertechnicaldetails" statement 1

postgres `order by` argument type

What is the argument type for the order by clause in Postgresql?
I came across a very strange behaviour (using Postgresql 9.5). Namely, the query
select * from unnest(array[1,4,3,2]) as x order by 1;
produces 1,2,3,4 as expected. However the query
select * from unnest(array[1,4,3,2]) as x order by 1::int;
produces 1,4,3,2, which seems strange. Similarly, whenever I replace 1::int with whatever function (e.g. greatest(0,1)) or even case operator, the results are unordered (on the contrary to what I would expect).
So which type should an argument of order by have, and how do I get the expected behaviour?
This is expected (and documented) behaviour:
A sort_expression can also be the column label or number of an output column
So the expression:
order by 1
sorts by the first column of the result set (as defined by the SQL standard)
However the expression:
order by 1::int
sorts by the constant value 1, it's essentially the same as:
order by 'foo'
By using a constant value for the order by all rows have the same sort value and thus aren't really sorted.
To sort by an expression, just use that:
order by
case
when some_column = 'foo' then 1
when some_column = 'bar' then 2
else 3
end
The above sorts the result based on the result of the case expression.
Actually I have a function with an integer argument which indicates the column to be used in the order by clause.
In a case when all columns are of the same type, this can work: :
SELECT ....
ORDER BY
CASE function_to_get_a_column_number()
WHEN 1 THEN column1
WHEN 2 THEN column2
.....
WHEN 1235 THEN column1235
END
If columns are of different types, you can try:
SELECT ....
ORDER BY
CASE function_to_get_a_column_number()
WHEN 1 THEN column1::varchar
WHEN 2 THEN column2::varchar
.....
WHEN 1235 THEN column1235::varchar
END
But these "workarounds" are horrible. You need some other approach than the function returning a column number.
Maybe a dynamic SQL ?
I would say that dynamic SQL (thanks #kordirko and the others for the hints) is the best solution to the problem I originally had in mind:
create temp table my_data (
id serial,
val text
);
insert into my_data(id, val)
values (default, 'a'), (default, 'c'), (default, 'd'), (default, 'b');
create function fetch_my_data(col text)
returns setof my_data as
$f$
begin
return query execute $$
select * from my_data
order by $$|| quote_ident(col);
end
$f$ language plpgsql;
select * from fetch_my_data('val'); -- order by val
select * from fetch_my_data('id'); -- order by id
In the beginning I thought this could be achieved using case expression in the argument of the order by clause - the sort_expression. And here comes the tricky part which confused me: when sort_expression is a kind of identifier (name of a column or a number of a column), the corresponding column is used when ordering the results. But when sort_expression is some value, we actually order the results using that value itself (computed for each row). This is #a_horse_with_no_name's answer rephrased.
So when I queried ... order by 1::int, in a way I have assigned value 1 to each row and then tried to sort an array of ones, which clearly is useless.
There are some workarounds without dynamic queries, but they require writing more code and do not seem to have any significant advantages.

invalid input syntax for integer: "9Na_(2)SO_(4)"

I'm trying to insert a alphanumeric value in a table:
INSERT INTO solution (solution, nextsolution) VALUES
('9Na_(2)SO_(4)', NULL), ('2Ni(OH)_(3)', (SELECT id FROM solution WHERE solution='9Na_(2)SO_(4)' & nextsolution=null));
solution is of type text and nextsolution is an integer. Unfortunately postgresql doesn't allow me to do the WHERE clause. It gives me the error:
ERROR: invalid input syntax for integer: "9Na_(2)SO_(4)"
LINE 9: ...OH)_(3)', (SELECT id FROM solution WHERE solution='9Na_(2)SO...
How can I solve this?
The issue is that the statement in the where clause: '9Na_(2)SO_(4)' & nextsolution=null tries to do a bitwise and (&) operation on the string and this won't work (and probably isn't what you want anyway).
Looking at your query I think what you want is to first insert the value '9Na_(2)SO_(4)' and then the value '2Ni(OH)_(3)' with the id of the previous inserted row.
You need to do this as two statements and use a different syntax. This should do what you want:
INSERT INTO solution (solution, nextsolution) VALUES (
'9Na_(2)SO_(4)',
NULL
);
INSERT INTO solution (solution, nextsolution) VALUES (
'2Ni(OH)_(3)',
(SELECT id FROM solution WHERE solution='9Na_(2)SO_(4)' and nextsolution is null)
);
You need to use AND instead of & to join your WHERE clause - an ampersand (&) is used for bitwise operations.

Postgres query error

I have a query in postgres
insert into c_d (select * from cd where ak = '22019763');
And I get the following error
ERROR: column "region" is of type integer but expression is of type character varying
HINT: You will need to rewrite or cast the expression.
An INSERT INTO table1 SELECT * FROM table2 depends entirely on order of the columns, which is part of the table definition. It will line each column of table1 up with the column of table2 with the same order value, regardless of names.
The problem you have here is whatever column from cd with the same order value as c_d of the table "region" has an incompatible type, and an implicit typecast is not available to clear the confusion.
INSERT INTO SELECT * statements are stylistically bad form unless the two tables are defined, and will forever be defined, exactly the same way. All it takes is for a single extra column to get added to cd, and you'll start getting errors about extraneous extra columns.
If it is at all possible, what I would suggest is explicitly calling out the columns within the SELECT statement. You can call a function to change type within each of the column references (or you could define a new type cast to do this implicitly -- see CREATE CAST), and you can use AS to set the column label to match that of your target column.
If you can't do this for some reason, indicate that in your question.
Check out the PostgreSQL insert documentation. The syntax is:
INSERT INTO table [ ( column [, ...] ) ]
{ DEFAULT VALUES | VALUES ( { expression | DEFAULT } [, ...] ) | query }
which here would look something like:
INSERT INTO c_d (column1, column2...) select * from cd where ak = '22019763'
This is the syntax you want to use when inserting values from one table to another where the column types and order are not exactly the same.