Help with NHibernate query - nhibernate

I have 2 tables, Plan and Ticket. I want all the records that are in TravelPlan but not in Ticket.
Template.Criteria.CreateCriteria("Plan")
.Add(Subqueries.PropertyNotIn("UserID",
DetachedCriteria.For(typeof(Ticket))
.SetProjection(Projections.Property("UID"))));
The above query doesnt return any records..

I can't guess what SearchTemplate does, but you are applying the projection to the outer criteria instead of the detached one.
Also, the "root" criteria should be for TravelPlan, not Ticket.
In other words:
criteria = DetachedCriteria.For<TravelPlan>()
.Add(Subqueries.PropertyNotIn(
"UserId",
DetachedCriteria.For<Ticket>()
.SetProjection(Projections.Property("UID"))))
This assumes TravelPlan has a UserID property that is matches the UID property in Ticket.

Related

Executing raw sql queries with rails Active record methods

I have a situation like finding the persons who matches the filter applied. For that I have constructed query(select ids of people who matches filter condition) for persons who matches the filter. and then get the person details for the filtered people.
m = ActiveRecord::Base.connection.exec_query(filter_blocks_query.join(' INTERSECT ')) unless filter_blocks_query.empty?
Person.where(id: m.rows.flatten)
But this executes the result and then filters people who matches the filtered IDs. Is there any ways to make it like a single query.
filter_blocks_query is raw sql statement.

Rails ActiveRecord query where relationship does not exist based on third attribute

I have an Adventure model, which is a join table between a Destination and a User (and has additional attributes such as zipcode and time_limit). I want to create a query that will return me all the Destinations where an Adventure between that Destination and the User currently trying to create an Adventure does not exist.
The way the app works when a User clicks to start a new Adventure it will create that Adventure with the user_id being that User's id and then runs a method to provide a random Destination, ex:
Adventure.create(user_id: current_user.id) (it is actually doing current_user.adventures.new ) but same thing
I have tried a few things from writing raw SQL queries to using .joins. Here are a few examples:
Destination.joins(:adventures).where.not('adventures.user_id != ?'), user.id)
Destination.joins('LEFT OUTER JOIN adventure ON destination.id = adventure.destination_id').where('adventure.user_id != ?', user.id)
The below should return all destinations that user has not yet visited in any of his adventures:
destinations = Destination.where('id NOT IN (SELECT destination_id FROM adventures WHERE user_id = ?)', user.id)
To select a random one append one of:
.all.sample
# or
.pluck(:id).sample
Depending on whether you want a full record or just id.
No need for joins, this should do:
Destination.where(['id not in ?', user.adventures.pluck(:destination_id)])
In your first attempt, I see the problem to be in the usage of equality operator with where.not. In your first attempt:
Destination.joins(:adventures).where.not('adventures.user_id != ?'), user.id)
you're doing where.not('adventures.user_id != ?'), user.id). I understand this is just the opposite of what you want, isn't it? Shouldn't you be calling it as where.not('adventures.user_id = ?', user.id), i.e. with an equals =?
I think the following query would work for the requirement:
Destination.joins(:adventures).where.not(adventures: { user_id: user.id })
The only problem I see in your second method is the usage of destinations and adventures table in both join and where conditions. The table names should be plural. The query should have been:
Destination
.joins('LEFT OUTER JOIN adventures on destinations.id = adventures.destination_id')
.where('adventures.user_id != ?', user.id)
ActiveRecord doesn't do join conditions but you can use your User destinations relation (eg a has_many :destinations, through: adventures) as a sub select which results in a WHERE NOT IN (SELECT...)
The query is pretty simple to express and doesn't require using sql string shenanigans, multiple queries or pulling back temporary sets of ids:
Destination.where.not(id: user.destinations)
If you want you can also chain the above realation with additional where terms, ordering and grouping clauses.
I solved this problem with a mix of this answer and this other answer and came out with:
destination = Destination.where
.not(id: Adventure.where(user: user)
.pluck(:destination_id)
)
.sample
The .not(id: Adventure.where(user: user).pluck(:destination_id)) part excludes destinations present in previous adventures of the user.
The .sample part will pick a random destination from the results.

NHibernate Criteria Subquery help

I am using NHibernate and I my requirement is that I have 2 tables, User and Ticket. I want all the records that are in User but not in Ticket. The Ticket table has UserId as reference key to the Primary key ID of User table. Below is my code,
RegNotTickTemplate.Criteria = DetachedCriteria.For(typeof(User));
RegNotTickTemplate.Criteria.Add(Subqueries.PropertyNotIn("ID",DetachedCriteria.For(typeof(Ticket))
.SetProjection(Projections.Property("UserID"))));
The above query doesnt return correct set of records.
As an alternative, you could try using HQL. I never use Criteria as I find HQL more readable (it is almost the same as SQL except you get to query based on the entities rather than the tables).
Chapter 13. HQL: The Hibernate Query Language
IQuery query = Session.CreateQuery(
"from User where Id not in (select UserId from Ticket)");
query.List<User>();
If that is still no good, you can always do an SQL query
ISQLQuery query = Session.CreateSQLQuery(sql);
What you are missing is: the count of tickets for this user should be greater than zero. Here is how you can implement it:
RegNotTickTemplate.Criteria = DetachedCriteria.For(typeof(User));
RegNotTickTemplate.Criteria.Add(Subqueries.PropertyIn("Id",
DetachedCriteria.For<Ticket>()
.SetProjection(Projections.GroupProperty("User"))
.Add(Restrictions.Eq(Projections.RowCount(), 0))));
If you don't want the count of rows you can do the following:
RegNotTickTemplate.Criteria = DetachedCriteria.For(typeof(User),"user");
RegNotTickTemplate.Criteria.Add(Subqueries.Exists(DetachedCriteria.For<Ticket>("ticket")
.SetProjection(Projections.Property("User"))
.Add(Restrictions.EqProperty("user.Id", "User"))));

What is the best way to reduce sql queries in my situation

Here is the situation,each page will show 30 topics,so I had execute 1 sql statements at least,besides,I also want to show how many relpies with each topic and who the author is,thus
I have to use 30 statements to count the number of replpies and use other 30 statements to find the author.Finally,I got 61 statements,I really worry about the efficiency.
My tables looks like this:
Topic Reply User
------- ---------- ------------
id id id
title topic_id username
... ...
author_id
You should look into joining tables during a query.
Joins in SQLServer http://msdn.microsoft.com/en-us/library/ms191517.aspx
Joins in MySQL http://dev.mysql.com/doc/refman/5.0/en/join.html
As an example, I could do the following:
SELECT reply.id, reply.authorid, reply.text, reply.topicid,
topic.title,
user.username
FROM reply
LEFT JOIN topic ON (topic.id = reply.topicid)
LEFT JOIN user ON (user.id = reply.authorid)
WHERE (reply.isactive = 1)
ORDER BY reply.postdate DESC
LIMIT 10
If I read your requirements correctly, you want the result of the following query:
SELECT Topic.title, User.username, COUNT(Reply.topic_id) Replies
FROM Topic, User, Reply
WHERE Topic.id = Reply.topic_id
AND Topic.author_id = User.id
GROUP BY Topic.title, User.username
When I was first starting out with database driven web applications I had similar problems. I then spent several years working in a database rich environment where I actually learned SQL. If you intend to continue developing web applications (which I find are very fun to create) it would be worth your time to pick up a book or checking out some how-to's on basic and advance SQL.
One thing to add, on top of JOINS
It may be that your groups of data do not match or relate, so JOINs won't work. Another way: you may have 2 main chunks of data that is awkward to join.
Stored procedures can return multiple result sets.
For example, for a summary page you could return one aggregate result set and another "last 20" result set in one SQL call. To JOIN the 2 is awkward because it doesn't "fit" together.
You certainly can use some "left joins" on this one, however since the output only changes if someone updates/adds to your tables you could try to cache it in a xml/text file. Another way could be to build in some redundancy by adding another row to the topic table that keeps the reply count, username etc... and update them only if changes occur...

Count the number of rows in each group

Using CodeIgniter's Active Record class and MySQL, I have a table of posts with user_id and various other fields, and I want to count how many posts each user has made. I could get rows where user_id = $whatever and count the number of results, but I'd have to loop through every user_id and use that count_all_results() query over and over for each one.
There must be a better way! If every field just had a field with a 1 in it, I could select_sum up that field and get a count. But that seems dumb.
Many thanks in advance!
Using active record should be:
$this->db->select('field1, ... ,fieldn, count(1) as number_elements_of_row');
$this->db->group_by(array('field_group_1', ... ,'field_group_n'));
$result = $this->db->get('mytable');
so $result will have what you need!