Run Keyword If with SQL - frameworks

I am attempting to pull back data from a Restful web service.
If I get a text value that contains word A, then I need to run this SQL to verify, if it doesn't, run a different SQL.
This run Keyword If wants to run a keyword, but the Query statement starts with a variable.
This is what I've tried:
${typeA} Set Variable ${rowValues["TypeA"]}
${foundValue} Get Lines Containing String ${typeA} Speical
${lineCount} Get Line Count ${foundValue}
${resultValue} Set Variable If ${lineCount} > 0 ${True} ${False}
${idvalue} Set Variable test
Run Keyword If ${resultValue}
... ${idvalue} Query Select max(id) from test where 1 =1;
... ELSE
... ${idValue} Query Select max(id) from table 2 where 1 = 1;
I just get this error:
FAIL : No keyword with name 'test' found.

The first argument after the condition in Run keyword if must be a keyword. You are incorrectly giving it a variable (which presumably contains the string "test", based on the error you're reporting)
To assign the value of the query you must capture the result of Run keyword if:
${idValue}= Run keyword if ${resultValue}
... Query Select max(id) from test where 1 =1;
... ELSE
... Query Select max(id) from table 2 where i = 1;

Related

Postgres: Python: TypeError: SQL.__init__() takes 2 positional arguments but 3 were given

Hello I am getting error from my code, can someone help me please?
def query_builder(self, field_name, table_name, pkey, id):
queryx=sql.SQL("select {field} from {table} where {pkey} = %s",(id)).format(
field=sql.Identifier(field_name),
table=sql.Identifier(table_name),
pkey=sql.Identifier(pkey))
self.cur.execute(queryx.as_string(self.conn))
I'm going to assume you are using psycopg2.
If so the issues are, first:
"select {field} from {table} where {pkey} = %s",(id) ..."
Do not include the argument (id) in the string. Also this is not proper form for a single value in a tuple. Python requires it be (id,), note the comma.
Second:
self.cur.execute(queryx.as_string(self.conn))
Should be:
self.cur.execute(queryx, (id,))
The execute is where you supply the argument. Also the composable sql.SQL(...) can be passed directly to execute without being run through as_string. See here sql for more examples.
UPDATE
To use "*" there are two ways:
cur.execute(sql.SQL("select * from {table} where {pkey} = %s).format(table.sql.Identifier(table_name), pkey=sql.Identifier(pkey))
--OR
cur.execute(sql.SQL("select {field} from {table} where {pkey} = %s).format(field=sql.SQL("*"), table=sql.Identifier(table_name), pkey=sql.Identifier(pkey))
Warning, the second does allow for SQL injection as sql.SQL() does not escape values.
As to multiple fields the sql section of the docs has multiple examples. For instance:
If part of your query is a variable sequence of arguments, such as a comma-separated list of field names, you can use the SQL.join() method to pass them to the query:
query = sql.SQL("select {fields} from {table}").format(
fields=sql.SQL(',').join([
sql.Identifier('field1'),
sql.Identifier('field2'),
sql.Identifier('field3'),
]),
table=sql.Identifier('some_table'))

Why is my UPDATE query with jsonb popping an error?

I'm trying to update a row in my PostgreSQL database and it's saying it's not finding the x column. the thing is the column pg is trying to find is actually a parameter for the new value in the jsonb_set function, so I'm at my wits end.
It's hard to explain, so I included the query and the error it throws.
Tried adding quotes, double-quotes, brackets, inside and out... didn't work.
UPDATE public.sometable
SET somecolumn = jsonb_set(somecolumn, '{firstKey, secondKey}', someInputString), update_date=NOW(), update_username="someone#somewhere.com"
WHERE id=1
RETURNING *
I'm expecting the value of the row I'm updating to be returned, instead I get:
ERROR: column "someInputString" does not exist
LINE 1: ...n = jsonb_set(somecolumn , '{firstKey, secondKey}', someInputString)...
You have to deliver a valid json value as the third argument of the function:
UPDATE public.sometable
SET
somecolumn = jsonb_set(somecolumn, '{firstKey, secondKey}', '"someInputString"'),
update_date = now(),
update_username = 'someone#somewhere.com'
WHERE id = 1
RETURNING *
Note, I guess update_username is a text, so you should use single quotes for a simple text.
Db<>fiddle.

How to substitute psql script variables into strings in the query so it doesn't fail regardless if the variable is set or not

What I want is for the same query not to fail - regardless of the variable being set or not.
Then depending on the variable being set - returning relevant output.
Here's more or less what I mean/want:
--variable not set, returns not substituted string:
SELECT 'solution=:abc' result;
result
---------------
solution=:abc
--variable set:
\set abc 5+7
SELECT 'solution=:abc' result;
result
---------------
solution=5+7
BUT INSTEAD in both cases variable doesn't get substituted:
SELECT 'solution=:abc' result;
result
---------------
solution=:abc
--variable set:
\set abc 5+7
SELECT 'solution=:abc' result;
result
---------------
solution=:abc
I found that I need to use :'variable' syntax, so
SELECT 'solution=':'abc' result;
but this gives an extra (') sign there:
result
---------------
solution='5+7
and doesn't work when variable is not set
\unset abc
SELECT 'solution=':'abc' result;
ERROR: syntax error at or near ":"
LINE 1: SELECT 'solution=':'abc' result;
What's going on?
Any way to make it work in both cases as described at the top?
I am on PostgreSQL 9.6.11
psql's variable interpolation is syntax aware. If you want to use the variable
verbatim, use :abc;
as a string, use :'abc';
as an identifier (e.g. for a table name), use :"abc" (e.g. for a table name).
What you're trying to do is to combine two strings. Thus, syntactically the correct would be:
SELECT 'solution=' || :'abc' result;
The explanation as to why there's the extra quote when you do
SELECT 'solution=':'abc' result;
is that :'abc' gets replaced by '5+7', resulting in
SELECT 'solution=''5+7' result;
The double single quote is how you escape a single quote in a string, thus the single quote in your output.
As to how to make the query work when there is no variable set, I think there you're out of luck. The only workaround would be to initialize the variable to the variable name itself:
db=# \set abc :abc
db=# SELECT 'solution=' || :'abc' result;
result
---------------
solution=:abc

AREL: writing complex update statements with from clause

I tried looking for an example of using Arel::UpdateManager to form an update statement with a from clause (as in UPDATE t SET t.itty = "b" FROM .... WHERE ...), couldn.t find any. The way I've seen it, Arel::UpdateManager sets the main engine on initialization and allows to set the various fields and values to update. Is there actually a way to do this?
Another aside would be to find out how to express Postgres posix regex matching into ARel, but this might be impossible by now.
As far as I see the current version of arel gem is not support FROM keyword for the sql query. You can generate a query using the SET, and WHERE keywords only, like:
UPDATE t SET t.itty = "b" WHERE ...
and the code, which copies a value from field2 to field1 for the units table, will be like:
relation = Unit.all
um = Arel::UpdateManager.new(relation.engine)
um.table(relation.table)
um.ast.wheres = relation.wheres.to_a
um.set(Arel::Nodes::SqlLiteral.new('field1 = "field2"'))
ActiveRecord::Base.connection.execute(um.to_sql)
Exactly you can use the additional method to update a relation. So we create the Arel's UpdateManager, assigning to it the table, where clause, and values to set. Values shell be passed to the method as an argument. Then we need to add FROM keyword to the generated SQL request, we add it only if we have access to external table of the specified one by the UPDATE clause itself. And at the last we executes the query. So we get:
def update_relation!(relation, values)
um = Arel::UpdateManager.new(relation.engine)
um.table(relation.table)
um.ast.wheres = relation.wheres.to_a
um.set(values)
sql = um.to_sql
# appends FROM field to the query if needed
m = sql.match(/WHERE/)
tables = relation.arel.source.to_a.select {|v| v.class == Arel::Table }.map(&:name).uniq
tables.shift
sql.insert(m.begin(0), "FROM #{tables.join(",")} ") if m && !tables.empty?
# executes the query
ActiveRecord::Base.connection.execute(sql)
end
The you can issue the the relation update as:
values = Arel::Nodes::SqlLiteral.new('field1 = "field2", field2 = NULL')
relation = Unit.not_rejected.where(Unit.arel_table[:field2].not_eq(nil))
update_relation!(relation, values)

Manipulate & use the results of UPDATE .... RETURNING

Here is a simple PostgreSQL update returning some data:
UPDATE table set num = num + 1
WHERE condition = true
RETURNING table.id, table.num
Is there a way to further use the returned results, as if they came from a select statement? Something like this:
INSERT into stats
(id, completed)
SELECT c.id, TRUE
FROM
(
UPDATE table set num = num + 1
WHERE condition = true
RETURNING table.id, table.num
) c
where c.num > 5
Or do I have to save the returned results into my application, then create a new query out of the returned results?
As of version 9.1, you can use an UPDATE ... RETURNING in a "Common Table Expression" ("CTE"), which for most purposes can be thought of as a named sub-query.
So for your purposes, you could use something like this:
WITH update_result AS
(
UPDATE table set num = num + 1
WHERE condition = true
RETURNING table.id, table.num
)
INSERT into stats
(id, completed)
SELECT c.id, TRUE
FROM update_result as c
WHERE c.num > 5
If you're using a version of Postgres below 9.1, then I think you will have to grab the result into a variable in some procedural code - either your application, or a database function (probably written in PL/pgSQL).
That syntax won't work (unfortunately! that would be convenient).
Either you update and then create another query, or you do everything in a stored procedure where you can safely store and handle query resuts, so that you just have one single database call from your application.