Ecto fragment without parentheses - postgresql

My Postgres table structure:
id | stuff
--------+------------------------------------------------------------
123 | {"type1": {"ref": "ref_1", "...": "..."}, "type2": {"ref": "ref_1", "...": "..."}}
I'd like to query by ref in each type of stuff, I have a working SQL query for this:
SELECT * FROM "stuff" AS c0 CROSS JOIN jsonb_each(c0."stuff") AS f1 WHERE value->>'ref' = 'ref_1';
But using this Ecto query:
(from c in Stuff,
join: fragment("jsonb_each(?)", c.stuff),
where: fragment("value->>'ref' = ?", ^ref)
)
|> Repo.all
I get a Postgres syntax error in the CROSS JOIN statement:
** (Postgrex.Error) ERROR 42601 (syntax_error): syntax error at or near ")"
Inspecting the generated query:
[debug] QUERY ERROR source="stuff" db=0.3ms
SELECT ... FROM "stuff" AS c0 CROSS JOIN (jsonb_each(c0."stuff")) AS f1 WHERE (value->>'ref' = $1) ["ref_1"]
The above works when I remove the outer parentheses around (jsonb_each(c0."stuff")).
Is there a way to have the fragment generate the query without these parentheses or do I have to redesign the query?
Thanks

It seems that Ecto always wraps the join clause in parentheses, which is usually fine. The times when its not unfortunately includes certain calls like the jsonb_each above. There is a wiki here for such cases: The parentheses rules of PostgreSQL, is there a summarized guide?
The linked raw sql example had a much less upvoted answer that seems to work well with both making this query and getting back the expected struct.
sql = "SELECT * FROM "stuff" AS c0 CROSS JOIN jsonb_each(c0."stuff") AS f1 WHERE value->>'ref' = 'ref_1';"
result = JsonbTest.Repo.query!(sql)
Enum.map(result.rows, &JsonbTest.Repo.load(StuffStruct, {result.columns, &1}))

This is a bug in ecto, has been fixed here https://github.com/elixir-ecto/ecto/issues/2537

Related

Expression for Lookup activity result when stored procedure returns scalar value

I'm using a Lookup activity that returns an scalar result and I want to use that result to build a dinamic query using a concat expression. However, I'm receiving an error complaining that my SQL query is not well formated. This is how I'm building the query:
#concat('SELECT v.CscadaEventId as EventId,
v.EndDate as EndDateUtc
FROM v_cscadaevents v
INNER JOIN cscadaevents e
ON e.cscadaeventId = v.CscadaEventId
WHERE v.CscadaEventId IN(', activity('LookupUnfinishedAlarms').output.firstRow, ') AND e.EndDate IS NOT NULL;')
I expect that to return a query like this:
SELECT v.CscadaEventId as EventId,
v.EndDate as EndDateUtc
FROM v_cscadaevents v
INNER JOIN cscadaevents e
ON e.cscadaeventId = v.CscadaEventId WHERE v.CscadaEventId IN(2329390,2340616,2342078,2345857,2361240,2362088,2362574,2377062,2378594,2379357) AND e.EndDate IS NOT NULL;
I had see some examples where the lookup return multiple columns, and the right expression is activity('LookupUnfinishedAlarms').output.firstRow.myColumnName but what about when the lookup activity return an scalar value, as in my case?
This is the full error so far:
You have an error in your SQL syntax; check the manual that
corresponds to your MariaDB server version for the right syntax to use
near
'\"output\":\"2329390,2340616,2342078,2345857,2361240,2362088,2362574,2377062,237859'
at line
6,Source=Microsoft.DataTransfer.Runtime.GenericOdbcConnectors,''Type=System.Data.Odbc.OdbcException,Message=ERROR
[42000] [Microsoft][MariaDB] You have an error in your SQL syntax;
check the manual that corresponds to your MariaDB server version for
the right syntax to use near
'\"output\":\"2329390,2340616,2342078,2345857,2361240,2362088,2362574,2377062,237859'
at line 6,Source=MariaDBODBC_sb64.dll
Ok, just for the records, I found the solution. The expression must be:
#concat('SELECT v.CscadaEventId as EventId,
v.EndDate as EndDateUtc
FROM v_cscadaevents v
INNER JOIN cscadaevents e
ON e.cscadaeventId = v.CscadaEventId
WHERE v.CscadaEventId IN(', activity('LookupUnfinishedAlarms').output.firstRow.output, ') AND e.EndDate IS NOT NULL;')
So, the default column becomes output

PostgreSQL: Why does this join query throw a syntax error

I don't understand, why the following query produced an error. Whereas in other dbms (eg mysql) this sort of query is absolutely legal.
ERROR: Syntax error at the end of input
LINE 1: SELECT * FROM "addr_country" AS c JOIN "addr_state" AS s
^
SQL state: 42601
Character: 59
Adding an on-clause to the query makes it working:
SELECT * FROM "addr_country" AS c JOIN "addr_state" AS s
ON c."id" = s."country" AND s.id = 10
Due to this answer, MySQL makes a cross join out of a join w/o conditions

Orientdb sql , select from multiple tables

dont run "select from multiple tables" commands in orientdb 3.0 (centos)
i tested like this following commands
SELECT *
FROM Employee A, City B
WHERE A.city = B.id
Error Codes ; "Error parsing query: ^ Encountered " "SELECT "" at line 1, column 1. Was expecting one of: ... ... ";" ... DB name="
The most important difference between OrientDB and a Relational Database is that relationships are represented by LINKS instead of JOINs.
For this reason, the classic JOIN syntax is not supported. OrientDB uses the "dot (.) notation" to navigate LINKS. Example 1 : In SQL you might create a join such as:
SELECT *
FROM Employee A, City B
WHERE A.city = B.id
AND B.name = 'Rome'
In OrientDB an equivalent operation would be:
SELECT * FROM Employee WHERE city.name = 'Rome'
For more information: https://orientdb.com/docs/2.2.x/SQL.html#joins
Hope it helps
Regards

ALL query in Ecto

I need to translate the following SQL to Ecto Query DSL.
SELECT otc.*
FROM users u
INNER JOIN one_time_codes otc ON u.id = otc.user_id
LEFT OUTER JOIN one_time_code_invalidations otci ON otci.one_time_code_id = otc.id
WHERE u.id = 3 AND
otc.code = 482693 AND
otci.inserted_at IS NULL AND
otc.inserted_at > all(SELECT otc.inserted_at
FROM one_time_codes otc2
WHERE otc2.user_id = 3) AND
otc.inserted_at > (now() - '180 seconds'::interval);
In the third AND statement of WHERE clause, notice there is an ALL query. Ecto seems to not have corresponding function in Ecto.Query.API.
How to apply such aggregate? What is the correct way to implement this, though it could be implemented by having a lookup on debug logs of the Ecto, do you have another idea (or suggestion)?
Thank you.
Ecto does not allow subqueries in expressions, and you're right that there's no all in Ecto's Query API, but you can use fragment like this:
where: ...
and otc.inserted_at > fragment("all(SELECT otc.inserted_at FROM one_time_codes otc2 WHERE otc2.user_id = ?", 3)
and ...

PGSQL Error Code 42703 column does not exist

I have a database in postgreSQL. I want to read some data from there, but I get an error (column anganridref does not exist) when I execute my command.
Here is my NpgsqlCommand:
cmd.CommandText = "select * from angebot,angebotstatus,anrede where anrid=anganridref and anstaid=anganstaidref";
and my 3 tables
the names of my columns are rights. So I don't understand why that error comes. Someone can explain me why it does crash? Its not the problem of large and lowercase.
You are not prefixing your column names in the where clause:
select *
from angebot,
angebotstatus,
anrede
where anrid = anganridref <-- missing tablenames for the columns
and anstaid = anganstaidre
It's also recommended to use an explicit JOIN instead of the old SQL 89 implicit join syntax:
select *
from angebot
join angebotstatus on angebot.aaaa = angebotstatus.bbbb
join anrede on angebot.aaaa = anrede.bbbb