Postgres INSERT INTO query bug? - postgresql

What's wrong with the following Postgres query?
INSERT INTO kayak.airports(name, x, y, city) VALUES( $name, $x, $y, $city)
WHERE airport_id='$airport_id
EDIT (thanks Donnie for helping me make progress) :
I tried:
$query="UPDATE kayak.airports SET name=$name, x = $x, y = $y, city = $city
WHERE airports.airport_id='$airport_id'";
It said "column 'Brisbane' doesn't exist" (Brisbane is the first city to be inserted. ) I took out everything between SET and WHERE except for "x=$x" and those were successfully inserted. Ditto for "y=$y". When only leaving in name=$name it says
"Query failed: ERROR: syntax error at or near "International" LINE 1: UPDATE kayak .airports SET name=Brisbane International WHERE... ^"

Your query string is not quoted. Do not use PHP variable interpolation for building SQL queries, because this will leave your script or application vulnerable to an SQL injection attack.
Instead, use parameterized queries. Thus, your query above becomes:
$query = 'UPDATE kayak.airports SET name = $1, x = $2, y = $3, city = $4'.
'WHERE airports.airport_id = $5';
Then, you will use the parameterized query calling function pg_query_paramsto pass the required parameters:
$result = pg_query_params($query, $parameters)
Where $parameters is an array of parameters.
Also note that the $query string is single-quoted, because the $n placeholders are not there for interpolation. This prevents any mistakes (such as typing a real variable name by bumping a letter first) and eliminates any possibility of SQL injection.

You're attempting to insert literal values. A where clause makes no sense.
For insert, you can only use where in an insert ... select to limit what the select is returning.
Perhaps you actually want to update an existing record?

For me, if I get an error that a column doesn't exist, it's usually a tipoff that I've quoted something incorrectly (or not at all).
This is borne out by the error message from your attempt to update only the name field:
ERROR: syntax error at or near "International" LINE 1:
(The carat should point right to the problem area in the query.)
The value you are passing to the name field in your UPDATE statement needs to be quoted, just like the value you're passing to airport_id. (I'm going to take a wild guess that x and y are integers, which wouldn't require quoting, which is why you don't get an error when you try to update just those field.) (I'm going to take another wild guess that the value you pass to city will need to be quoted too, but you will probably figure that out shortly. :) )
The end result expanded UPDATE should look something like this:
UPDATE kayak.airports
SET name='Brisbane International', x = 123, y = 456, city = 'Brisbane'
WHERE ...

Related

Filemaker GetAsNumber on ExecuteSQL

I have a calculation for a field like this:
GetAsNumber(
ExecuteSQL (
"SELECT nb FROM something WHERE value = ?" ;
"" ;
"" ;
amount
)
)
Everything works fine as long as the returned number is single-digit. But when the SQL statement returns for example "12", then the number I get from the GetAsNumber function is suddenly 1212 instead of 12.
As I understand it, this has somehow to do with the format in which SQL results are returned, it says so in the documentation ("FileMaker Pro returns date, time, and number data in Unicode/SQL format, not in the locale of the operating system or the file.").
But I guess there must be a way to format back the result so it can be converted to a number.
The solution comes from by michael.hor257k's comment on my question:
ExecuteSQL returns an array (I wasn't aware of it, it's also not specified in the documentation where it says: "Data type returned: text"). So my problem had nothing to do with double digits (I guess I should have run more tests), but with the sql statement returning more than one result.
As in my case multiple results are always the same, I could alter my calculation in this way:
GetValue(
ExecuteSQL (
"SELECT nb FROM something WHERE value = ?" ;
"" ;
"" ;
amount
) ;
1
)
In this way I only retrieve the first result.
As michael.hor257k suggested in his comment, I could also restrict the SQL result to one row.
ExecuteSQL (
"SELECT nb FROM something WHERE value = ? FETCH FIRST ROW ONLY" ;
"" ;
"" ;
amount
)

How to pick up data from row and put it into tPostgresqlInput?

I have a requets which giving me an ids. I need to iterate them into another request, so I have a sheme like this: scheme
In tPostgresqlInput I have this code rc.id = upper('18ce317b-bf69-4150-b880-2ab739eab0fe') , but instead of id I need to put smthn like globalMap.get(row4.id). How did I do this?
Apparently this is a syntax issue
Try with :
"select * FROM table LEFT JOIN table on parameter JOIN table on parameter
WHERE 1=1 AND
column = 'content'
AND upper(rc.id) = upper('"+((String)globalMap.get("row4.id")) +"')"
Expressions in tDBInput should always begin and end with double quotes.
Don't forget to cast globalMap.get() with the type of your element (here I put String)
.equals is not a DB function but a java function. I have replaced it with '='
Let me know if it's better

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 write where Between query in Yii2 with integer as a second parameter

I have this query in PostgreSQL that I want to implement in my model in Yii2:
SELECT *
FROM some_table
WHERE 1492257600 BETWEEN start AND end
start and end are attributes of some_table.
In my model, I tried the following but, no matter how I write it, it keeps throwing the same error.
$results = static::find()->where(['between', 1492257600, 'start', 'end'])
->all();
This is the error I'm getting:
Undefined column: 7 ERROR: column \"1492257600\" does not exist
The SQL being executed was: SELECT * FROM \"some_table\" WHERE \"1492257600\" BETWEEN 'start' AND 'end'"
When the query is built, these symbols " " are added to the integer, so PostgreSQL thinks it is a column of the table.
Can anyone tell me how to write the where between correctly?
There is dedicated BetweenColumnsCondition expression for such cases:
use yii\db\conditions\BetweenColumnsCondition;
$results = static::find()
->where(new BetweenColumnsCondition(1492257600, 'BETWEEN', 'start', 'end'))
->all();
It automatically quotes column names and escapes value, so it should be more convenient than simple yii\db\Expression.
Also note that WHERE 1492257600 BETWEEN start AND end may be slower than WHERE 1492257600 >= start AND 1492257600 <= end, I suggest to do some performance test if your table may grow big and usage indexes is crucial.
I don't have experience with postgresql but this will work same as between,
$results = self::find()
->where(['>=', 'start', 1492257600])
->andWhere(['<=', 'end', 1492257600])
->all();
Refer to this: Yii2 Doc
When an Expression object is embedded within a SQL statement or fragment, it will be replaced with the $expression property value without any DB escaping or quoting.
so You'll have something like this:
$expression = new \yii\db\Expression('1492257600 BETWEEN start AND end');
$results = self::find()->where($expression)
->all();

How to get only specific rows on DB, when date range fits SQL condition on a 'tsrange' datatype? [duplicate]

I have this query:
some_id = 1
cursor.execute('
SELECT "Indicator"."indicator"
FROM "Indicator"
WHERE "Indicator"."some_id" = %s;', some_id)
I get the following error:
TypeError: 'int' object does not support indexing
some_id is an int but I'd like to select indicators that have some_id = 1 (or whatever # I decide to put in the variable).
cursor.execute('
SELECT "Indicator"."indicator"
FROM "Indicator"
WHERE "Indicator"."some_id" = %s;', [some_id])
This turns the some_id parameter into a list, which is indexable. Assuming your method works like i think it does, this should work.
The error is happening because somewhere in that method, it is probably trying to iterate over that input, or index directly into it. Possibly like this: some_id[0]
By making it a list (or iterable), you allow it to index into the first element like that.
You could also make it into a tuple by doing this: (some_id,) which has the advantage of being immutable.
You should pass query parameters to execute() as a tuple (an iterable, strictly speaking), (some_id,) instead of some_id:
cursor.execute('
SELECT "Indicator"."indicator"
FROM "Indicator"
WHERE "Indicator"."some_id" = %s;', (some_id,))
Your id needs to be some sort of iterable for mogrify to understand the input, here's the relevant quote from the frequently asked questions documentation:
>>> cur.execute("INSERT INTO foo VALUES (%s)", "bar") # WRONG
>>> cur.execute("INSERT INTO foo VALUES (%s)", ("bar")) # WRONG
>>> cur.execute("INSERT INTO foo VALUES (%s)", ("bar",)) # correct
>>> cur.execute("INSERT INTO foo VALUES (%s)", ["bar"]) # correct
This should work:
some_id = 1
cursor.execute('
SELECT "Indicator"."indicator"
FROM "Indicator"
WHERE "Indicator"."some_id" = %s;', (some_id, ))
Slightly similar error when using Django:
TypeError: 'RelatedManager' object does not support indexing
This doesn't work
mystery_obj[0].id
This works:
mystery_obj.all()[0].id
Basically, the error reads Some type xyz doesn't have an __ iter __ or __next__ or next function, so it's not next(), or itsnot[indexable], or iter(itsnot), in this case the arguments to cursor.execute would need to implement iteration, most commonly a List, Tuple, or less commonly an Array, or some custom iterator implementation.
In this specific case the error happens when the classic string interpolation goes to fill the %s, %d, %b string formatters.
Related:
How to implement __iter__(self) for a container object (Python)
Pass parameter into a list, which is indexable.
cur.execute("select * from tableA where id =%s",[parameter])
I had the same problem and it worked when I used normal formatting.
cursor.execute(f'
SELECT "Indicator"."indicator"
FROM "Indicator"
WHERE "Indicator"."some_id" ={some_id};')
Typecasting some_id to string also works.
cursor.execute(""" SELECT * FROM posts WHERE id = %s """, (str(id), ))