I want to realize the following (for this example: MySQL) statement in JPA 2.1 with Eclipselink as the implementation:
select *
from account
where (mailing_zip_code, id) > (56237, 275)
order by mailing_zip_code asc, id asc
limit 10;
What I want to achieve is an implementation of the seek method for endless scrolling without using an offset in the query. With focus on the where clause, I am not able to find a correct name for this construct. In some places it is called 'composite value', but I am not able to find results by this name, but it seems to be compliant with the SQL-92 standard.
This statement will be extended by filter parameters, so naturally I would like to build it with the JPA criteria API.
I searched the API for some time now, does anybody now if and how this is possible?
After realizing that
select *
from account
where (mailing_zip_code, id) > (56237, 275)
order by mailing_zip_code asc, id asc
limit 10;
is just a shorter way to write
select *
from account
where mailing_zip_code > '56237'
or (mailing_zip_code = '56237' AND id > 276)
order by mailing_zip_code asc, id asc
limit 10;
the criteria query was not that hard after all (appended just the predicate):
if (null != startId) {
Predicate dateGreater = cb.greaterThan(entity.get(sortBy), startValue);
Predicate dateEqual = cb.equal(entity.get(sortBy), startValue);
Predicate idGreater = cb.greaterThan(entity.get("id"), startId);
Predicate dateEqualAndIdGreater = cb.and(dateEqual, idGreater);
cb.or(dateGreater, dateEqualAndIdGreater);
}
If there is a nicer way, I would be very happy to learn about it.
Related
I am using MongoDB with hapi.JS. I have a collection which contains few rows in the schema. I want to sort the rows in either asc order or desc order but want to mention it in the URI. for example the URI should look something like this
/api/v1/customers?sort=name&direction=asc&limit=30
How can I sort this collection by asc or desc order and limit can be fixed or flexible as well.
I have defined like this as of now but even if I mention the sort in URI it gives the output only in asc order.
Models.Account.find(criteria,projection,{skip:5,limit:5},function(err,resp){
if(err)
callbackRoute(err);
else
callbackRoute(err,resp);
}).sort({[_id]:"asc"});
db.yourcollection.find(...).sort({ name:1 }).limit(30)
or with dynamic values:
// following is ECMA 6 only
// get params and make sure values are what you expect (check for injection) + direction must be = "asc" || "desc"
db.yourcollection.find(...).sort({ [sort]: direction }).limit(30)
Using Entity Framework and LINQ, I need to get row number together with an entity, e.g. for loan I have multiple invoices and I want to select specific invoice together with its sequence number.
Basically, I'd need to know how to write equivalent to this:
select
nr, i.*
from
[Invoices] i
inner join
(select
row_number() over (order by IssueDate) nr, id
from
[Invoices]
where
LoanId = 5) t on t.id = i.id
where
i.id = 207
According to this post ROW_NUMBER is not supported in L2E. If you don't mind the overhead of loading all invoices for a given LoanId into memory, then it can be be done easily in C# with the overload of the Select method on IEnumerable that produces an index for each item, e.g.:
//First select the invoices
var invoices = from i in dbContext.Invoices
where i.LoanId == 5
order by i.IssueDate
select i;
var indexedInvoice = invoices.ToList().Select((i, count) => new { Invoice = i, RowCount = count })
.First(ii => ii.Invoice.Id == 207);
I can see how this can be less than optimal in some situations, so you might consider bypassing L2E here and execute your query as a plain old sql string, depending on how performance-critical it is, and on how many invoices there usually are for a single loan.
I am using mysql 5.5 with openjpa 2.3.0.
I have entities with namedQueries (generated in netbeans - I would like to be able to use this), for example:
#NamedQuery(name = "User.findAll", query = "SELECT u FROM User u")
#NamedQuery(name = "User.findByGender", query = "SELECT u FROM User u WHERE u.gender = :gender")
I am creating restfull aplication with paged results. I would like to return for every paged result the Content-Range header as 1-20/250 where 20 is pagesize, 250 total count.
I tried to create a query
entityManager.createNativeQuery("SELECT count(1) FROM (" + namedQuery.toString() + ") as foo;");
where I could dynamicaly insert any named query and return the count without returning the result list -> it should be faster.
When I execute this, exception occurs
SQL state 42S22: Unknown column 'u' in 'field list'
Executing the query itself in entitymanager is ok.
Can I use the entity manager or criteria builder to create a query for counting results without returning the result list (and without writing for every namedQuery a count duplicate)? thank you for helping.
You are mixing JPQL with native queries. JPQL says SELECT u FROM entity u, SQL would be SELECT * FROM entity u or SELECT col1,col2,col3 FROM entity u
You could write a JPQL named query counting the stuff, e.g. SELECT COUNT(u) FROM entity u. A getSingleResult() would then return an Object[], whose first element contains the count.
Not nice but working. Why do You have to query for the number anyway? Pagination means next = lastindex+pagesize. if next < lastindex+pagesize, the end is reached.
When you retrieve data through a MySQLi statement such as the following:
$sqls = "SELECT * FROM course WHERE course='$product_id_array' OR course='Both' ORDER BY ...";
$sqlsresults = mysqli_query($db_conx,$sqls);
while($row = mysqli_fetch_assoc($sqlsresults)) {
$selectedContent = $row["content"];
$selectedTitle = $row["title"];
}
Is there a way to output the match for 'both' first? Would this be as simple as re-arranging the order of the WHERE portion of the statement?
Your ORDER BY explicitly sorts only by id. There is no way around this in the WHERE part of your query. To change how results are ordered, use ORDER BY.
SELECT *
FROM course
WHERE course=...
OR course='Both'
ORDER BY CASE course WHEN 'Both' THEN 0 ELSE 1 END ASC, id DESC
Unrelated note: if $product_id_array contains untrusted user input, the user can put things like '; DELETE FROM course; -- in there. Read up on parameterized queries to learn how to prevent that.
I'm using Flask-SQLAlchemy with PostgreSQL. I have the following two models:
class Course(db.Model):
id = db.Column(db.Integer, primary_key = True )
course_name =db.Column(db.String(120))
course_description = db.Column(db.Text)
course_reviews = db.relationship('Review', backref ='course', lazy ='dynamic')
class Review(db.Model):
__table_args__ = ( db.UniqueConstraint('course_id', 'user_id'), { } )
id = db.Column(db.Integer, primary_key = True )
review_date = db.Column(db.DateTime)#default=db.func.now()
review_comment = db.Column(db.Text)
rating = db.Column(db.SmallInteger)
course_id = db.Column(db.Integer, db.ForeignKey('course.id') )
user_id = db.Column(db.Integer, db.ForeignKey('user.id') )
I want to select the courses that are most reviewed starting with at least two reviews. The following SQLAlchemy query worked fine with SQlite:
most_rated_courses = db.session.query(models.Review, func.count(models.Review.course_id)).group_by(models.Review.course_id).\
having(func.count(models.Review.course_id) >1) \ .order_by(func.count(models.Review.course_id).desc()).all()
But when I switched to PostgreSQL in production it gives me the following error:
ProgrammingError: (ProgrammingError) column "review.id" must appear in the GROUP BY clause or be used in an aggregate function
LINE 1: SELECT review.id AS review_id, review.review_date AS review_...
^
'SELECT review.id AS review_id, review.review_date AS review_review_date, review.review_comment AS review_review_comment, review.rating AS review_rating, review.course_id AS review_course_id, review.user_id AS review_user_id, count(review.course_id) AS count_1 \nFROM review GROUP BY review.course_id \nHAVING count(review.course_id) > %(count_2)s ORDER BY count(review.course_id) DESC' {'count_2': 1}
I tried to fix the query by adding models.Review in the GROUP BY clause but it did not work:
most_rated_courses = db.session.query(models.Review, func.count(models.Review.course_id)).group_by(models.Review.course_id).\
having(func.count(models.Review.course_id) >1) \.order_by(func.count(models.Review.course_id).desc()).all()
Can anyone please help me with this issue. Thanks a lot
SQLite and MySQL both have the behavior that they allow a query that has aggregates (like count()) without applying GROUP BY to all other columns - which in terms of standard SQL is invalid, because if more than one row is present in that aggregated group, it has to pick the first one it sees for return, which is essentially random.
So your query for Review basically returns to you the first "Review" row for each distinct course id - like for course id 3, if you had seven "Review" rows, it's just choosing an essentially random "Review" row within the group of "course_id=3". I gather the answer you really want, "Course", is available here because you can take that semi-randomly selected Review object and just call ".course" on it, giving you the correct Course, but this is a backwards way to go.
But once you get on a proper database like Postgresql you need to use correct SQL. The data you need from the "review" table is just the course_id and the count, nothing else, so query just for that (first assume we don't actually need to display the counts, that's in a minute):
most_rated_course_ids = session.query(
Review.course_id,
).\
group_by(Review.course_id).\
having(func.count(Review.course_id) > 1).\
order_by(func.count(Review.course_id).desc()).\
all()
but that's not your Course object - you want to take that list of ids and apply it to the course table. We first need to keep our list of course ids as a SQL construct, instead of loading the data - that is, turn it into a derived table by converting the query into a subquery (change the word .all() to .subquery()):
most_rated_course_id_subquery = session.query(
Review.course_id,
).\
group_by(Review.course_id).\
having(func.count(Review.course_id) > 1).\
order_by(func.count(Review.course_id).desc()).\
subquery()
one simple way to link that to Course is to use an IN:
courses = session.query(Course).filter(
Course.id.in_(most_rated_course_id_subquery)).all()
but that's essentially going to throw away the "ORDER BY" you're looking for and also doesn't give us any nice way of actually reporting on those counts along with the course results. We need to have that count along with our Course so that we can report it and also order by it. For this we use a JOIN from the "course" table to our derived table. SQLAlchemy is smart enough to know to join on the "course_id" foreign key if we just call join():
courses = session.query(Course).join(most_rated_course_id_subquery).all()
then to get at the count, we need to add that to the columns returned by our subquery along with a label so we can refer to it:
most_rated_course_id_subquery = session.query(
Review.course_id,
func.count(Review.course_id).label("count")
).\
group_by(Review.course_id).\
having(func.count(Review.course_id) > 1).\
subquery()
courses = session.query(
Course, most_rated_course_id_subquery.c.count
).join(
most_rated_course_id_subquery
).order_by(
most_rated_course_id_subquery.c.count.desc()
).all()
A great article I like to point out to people about GROUP BY and this kind of query is SQL GROUP BY techniques which points out the common need for the "select from A join to (subquery of B with aggregate/GROUP BY)" pattern.