Neo4j - ORDER BY syntax error - neo4j

This cipher query is throwing the syntax error when I am sorting the result on relationship property using ORDER BY clause.
My query:
$MATCH(a{word:"review"})-[co:coocr]->(b) RETURN co LIMIT 20 ORDER BY co.val DESC
Syntax Error report:
Invalid input 'R': expected 'p/P' (line 4, column 2 (offset: 60))
"ORDER BY co.val DESC"
^
where the relationship co exists a property like "val:0.66" where value is a double valued number.
Please some one suggest where I am missing out.

Just reverse the order of the LIMIT and ORDER BY clauses:
MATCH (a{word:"review"})-[co:coocr]->(b)RETURN co ORDER BY co.val DESC LIMIT 20;

Related

How to CAST one attribute to INTEGER then group and sum

I would like to do the following with a query/SQL in Rails:
Collect a batch of Orders, selecting :buyer_id and :weight_lb.
Convert every weight_lb from a string (like "12.3lb" to an integer 12).
Sum all the weight_lb and group by buyer_id.
The output should look like: {buyer_id_1: 65, buyer_id_2: 190}, etc., where each number is the sum of each buyer's order weights.
This is what I've tried:
Order.find_by_sql("SELECT \"orders\".\"id\", \"orders\".\"buyer_id\", CAST(\"orders\".\"weight_lb\" AS DECIMAL) FROM \"orders\" LIMIT 500 OFFSET 1000")
=> [
#<Order:0x0000000118054830 id: 15076494, buyer_id: 22918, weight_lb: "315.0">,
#<Order:0x0000000118054918 id: 15076495, buyer_id: 22918, weight_lb: "110.0">,
...]
Despite CAST() as DECIMAL, the weight is still output as a string.
When I try to CAST() as INTEGER, it fails entirely with PG::InvalidTextRepresentation: ERROR: invalid input syntax for type integer: "315.0" (ActiveRecord::StatementInvalid)
What I would ideally like to have is:
{
15076494: 425, # Sum of all weights for the ID 15076494
15076495: 0,
15076496: 95, ...
}
I'm just not sure how to get there efficiently using Postgres.
We can use a combination of REPLACE, CAST and SUM operations
Order
.select("buyer_id, SUM(CAST(REPLACE(weight_lb, 'lb', '') AS DECIMAL)) AS weight_lb")
.group("buyer_id")
.limit(500)
.offset(1000)
The generated SQL will be:
SELECT "orders"."buyer_id", SUM(CAST(REPLACE("orders"."weight_lb", 'lb', '') AS DECIMAL)) AS weight_lb
FROM "orders"
GROUP BY "orders"."buyer_id"
LIMIT 500
OFFSET 1000
Let me know if it helps. :)

Obtain Union all result in ActiveRecord

Hows do one obtain the UNION operation result in Rails.
Given I have the following SQL statement
SELECT "sip_trunks".* FROM "sip_trunks" WHERE "sip_trunks"."default" = t LIMIT 1 UNION ALL SELECT "sip_trunks".* FROM "sip_trunks" WHERE "sip_trunks"."default" = f LIMIT 1
Thus far I have managed to construct the SQL using AREL with union all statement.
SipTrunk.where(default: true).limit(1).union(:all,SipTrunk.where(default: false).limit(1))
But attempting to query this result and AREL i.e Arel::Nodes::UnionAll and I'm unable to obtain the DB result.
Also running to_sql on the statement yield a SQL like this..
( SELECT "sip_trunks".* FROM "sip_trunks" WHERE "sip_trunks"."default" = $1 LIMIT 1 UNION ALL SELECT "sip_trunks".* FROM "sip_trunks" WHERE "sip_trunks"."default" = $2 LIMIT 1 )
this seem like a prepared statement but I don't see any prepared statement in DB
Attempting to use the above SQL using find_by_sql
SipTrunk.find_by_sql(SipTrunk.where(default: true).limit(1).union(:all,SipTrunk.where(default: false).limit(1)).to_sql,[['default',true],['default',false]])
with following error
ActiveRecord::StatementInvalid: PG::SyntaxError: ERROR: syntax error at or near "UNION"
LINE 1: ...trunks" WHERE "sip_trunks"."default" = $1 LIMIT 1 UNION ALL ...
How do I get the final SQL rows, from here?
Here is how I would perform this operation.
sql1 = SipTrunk.where(default: true).limit(1).arel
sql2 = SipTrunk.where(default: false).limit(1).arel
subquery = Arel::Nodes::As.new(
Arel::Nodes::UnionAll.new(sql1,sql2),
SipTrunk.arel_table
)
SipTrunk.from(subquery)
This will result in the following SQL
SELECT
sip_trunks.*
FROM
( SELECT
sip_trunks.*
FROM
sip_trunks
WHERE
sip_trunks.default = t
LIMIT 1
UNION ALL
SELECT
sip_trunks.*
FROM
sip_trunks
WHERE
sip_trunks.default = f
LIMIT 1) AS sip_trunks
And this will return an ActiveRecord::Relation of SipTrunk objects.
You can do a union like this, concatenating the two sql queries.
sql1 = SipTrunk.where(default: true).limit(1).to_sql
sql2 = SipTrunk.where(default: false).limit(1).to_sql
#sip_trunks = SipTrunk.find_by_sql("(#{sql1}) UNION (#{sql2})")
If you want to be fancy or have more than one sql queries to join you can to this
final_sql = [sql1, sql2].join(' UNION ')
#sip_trunks = SipTrunk.find_by_sql(final_sql)

Better method to find the second largest element in ruby on rails active record query

I am using this query to find the 2nd largest element. I am making query on value column.
Booking.where("value < ?", Booking.maximum(:value)).last
Is there any better query than this? Or any alternative to this.
PS - value is not unique. There could be two elements with same value
This should work.
Booking.select("DISTINCT value").order('value DESC').offset(1).limit(1)
Which will generate this query :
SELECT DISTINCT value FROM "bookings" ORDER BY value DESC LIMIT 1 OFFSET 1
You can use offset and last:
Booking.order(:value).offset(1).last
Which will produce following SQL statement:
SELECT `bookings`.* FROM `bookings`
ORDER BY `bookings`.`value` DESC
LIMIT 1 OFFSET 1

Rails exec_query bindings ignored

I'm trying to use exec_query to run an arbitrary query, with values brought in through bindings, and am getting unexpected errors.
Running this in the console
sql = 'SELECT * FROM foobars WHERE id IN (?)'
name = 'query_name_placeholder'
binds = [FooBar.first]
ActiveRecord::Base.connection.exec_query sql, name, binds
Yields this error:
Account Load (7.9ms) SELECT "foobars".* FROM "foobars" ORDER BY "foobars"."id" ASC LIMIT 1
PG::SyntaxError: ERROR: syntax error at or near ")"
LINE 1: SELECT * FROM foobars WHERE id IN (?)
^
: SELECT * FROM foobars WHERE id IN (?)
ActiveRecord::StatementInvalid: PG::SyntaxError: ERROR: syntax error at or near ")"
LINE 1: SELECT * FROM foobars WHERE id IN (?)
^
: SELECT * FROM accounts WHERE id IN (?)
from /Users/foo_user/.rvm/gems/ruby-2.2.4#foo_project/gems/activerecord-4.2.3/lib/active_record/connection_adapters/postgresql_adapter.rb:641:in `prepare'
It appears the binding syntax is being ignored? I've tried ... WHERE id = ? as well, but to no avail.
mu is too short got you part of the way there. For reference, here is the method's documentation: https://apidock.com/rails/ActiveRecord/ConnectionAdapters/DatabaseStatements/exec_query
He's right in that you will need to use the underlying database's binds syntax to set bind variables in the SQL string. For Oracle this is :1, :2 for PostgreSQL this is $1, $2... so that's step one.
Step two is you need to build bind objects, which are QueryAttribute objects, not just values to be passed in. This is a bit clunky, but here's an example:
binds = [ ActiveRecord::Relation::QueryAttribute.new(
"id", 6, ActiveRecord::Type::Integer.new
)]
ApplicationRecord.connection.exec_query(
'SELECT * FROM users WHERE id = $1', 'sql', binds
)
I just spent a whole day going through unit tests and source code trying to figure that out.

Solving a PG::GroupingError: ERROR

The following code gets all the residences which have all the amenities which are listed in id_list. It works with out a problem with SQLite but raises an error with PostgreSQL:
id_list = [48, 49]
Residence.joins(:listed_amenities).
where(listed_amenities: {amenity_id: id_list}).
references(:listed_amenities).
group(:residence_id).
having("count(*) = ?", id_list.size)
The error on the PostgreSQL version:
What do I have to change to make it work with PostgreSQL?
A few things:
references should only be used with includes; it tells ActiveRecord to perform a join, so it's redundant when using an explicit joins.
You need to fully qualify the argument to group, i.e. group('residences.id').
For example,
id_list = [48, 49]
Residence.joins(:listed_amenities).
where(listed_amenities: { amenity_id: id_list }).
group('residences.id').
having('COUNT(*) = ?", id_list.size)
The query the Ruby (?) code is expanded to is selecting all fields from the residences table:
SELECT "residences".*
FROM "residences"
INNER JOIN "listed_amenities"
ON "listed_amentities"."residence_id" = "residences"."id"
WHERE "listed_amenities"."amenity_id" IN (48,49)
GROUP BY "residence_id"
HAVING count(*) = 2
ORDER BY "residences"."id" ASC
LIMIT 1;
From the Postgres manual, When GROUP BY is present, it is not valid for the SELECT list expressions to refer to ungrouped columns except within aggregate functions or if the ungrouped column is functionally dependent on the grouped columns, since there would otherwise be more than one possible value to return for an ungrouped column.
You'll need to either group by all fields that aggregate functions aren't applied to, or do this differently. From the query, it looks like you only need to scan the amentities table to get the residence ID you're looking for:
SELECT "residence_id"
FROM "listed_amenities"
WHERE "listed_amenities"."amenity_id" IN (48,49)
GROUP BY "residence_id"
HAVING count(*) = 2
ORDER BY "residences"."id" ASC
LIMIT 1
And then fetch your residence data with that ID. Or, in one query:
SELECT "residences".*
FROM "residences"
WHERE "id" IN (SELECT "residence_id"
FROM "listed_amenities"
WHERE "listed_amenities"."amenity_id" IN (48,49)
GROUP BY "residence_id"
HAVING count(*) = 2
ORDER BY "residences"."id" ASC
LIMIT 1
);

Resources