What is the HQL equivalent of this SQL? - nhibernate

SELECT *
FROM [Group] g
INNER JOIN User2Group ug
**on g.Id != ug.GroupId**
INNER JOIN [Activity] a
on a.Id = g.ActivityId
WHERE g.UserId != 2
AND a.Lineage like '0,1,%'
Group > 1-n > User2Group < n-1 < User
m-n relationship
Activity > 1-n > Group
1-n
Trying to get all groups that a user has not already added to their account.
What I have so far:
var groups = repository.SimpleQuery<Group>("from Group as g join fetch g.Users as u join fetch g.Activity as a where g.Type != ? and a.Lineage like ? and g.CreatedBy.Id != ?", Group.GroupType.Deleted, string.Format("{0}%", lineage), currentUser.Id);
What has me tripped up is the "on g.Id != ug.GroupID"

It's a bit hard when I don't see the entities and the mappings, but the
on g.Id != ug.GroupId
part could probably be expressed in HQL by
from Group as g where g.id not in (select u.group.id from User u where u.id = ?)
The rest of the where clause should be easy to add.
Mind that it's been a while since I worked with HQL :-)

Related

selective count in a group by

I'm trying to make a report about the state of our clubs and their teams for the current season. A club can have many teams and each team has season-specific information (like image_url) in the table season_team.
I want to know how many teams already entered any season-specific information and how many uploaded an image. Following SQL is incorrect SQL, but maybe my intention comes across:
SELECT
t.club_id,
count(distinct t.id) as team_count,
count(st.id) WHERE st.id IS NOT null as season_team_count,
count(st.id) WHERE st.image_url IS NOT null as teams_with_image,
count(st.id) WHERE st.state = 'APPROVED' as approved_teams,
count(st.id) WHERE st.state = 'REJECTED' as rejected_teams
FROM
team t
LEFT OUTER JOIN season_team st ON (st.team_id = t.id and st.season_id = 8)
GROUP BY
t.club_id
can anyone point me in the right direction how to do this best?
I know I can do a dirty trick by just doing a "count(distinct st.image_url) -1" to get all the different images and substract 1 for the null entry. But that wouldn't work for the approved_teams
You can use FILTER:
SELECT t.club_id,
count(distinct t.id) as team_count,
count(st.id) FILTER (WHERE st.id IS NOT null) as season_team_count,
count(st.id) FILTER (WHERE st.image_url IS NOT null) as teams_with_image,
count(st.id) FILTER (WHERE st.state = 'APPROVED') as approved_teams,
count(st.id) FILTER (WHERE st.state = 'REJECTED') as rejected_teams
FROM team t LEFT OUTER JOIN
season_team st
ON st.team_id = t.id and st.season_id = 8
GROUP BY t.club_id

SQL - How to get a user's favorite posts title from StackExchange Database

I am working on a project analyzing Stackoverflow's user's behaviors and I need to get data from the stackoverflow, one of the data I need to get is to get a user's favorite posts title from stackexchange Database. Right now, I only figured out how to get the user's favorite information as following:
select VT.name, U.DisplayName
from VoteTypes VT, Votes V, Users U
where VT.Id = 5 and
VT.Id = V.VoteTypeId and
U.Id = V.UserId and
U.Id = '85597'
I think the next step is to find the posts the User voted, then match the userId. But I don't know if it is a right step to do. And I could not find any connection between a User's vote and a question post
SELECT
vt.name
, u.DisplayName
FROM VoteTypes vt
, Votes v <<<<<<<<< not good
, Users u <<<<<<<<< not good
WHERE vt.Id = 5
AND vt.Id = v.VoteTypeId <<<<<<<<< join predicate (vt = v)
AND u.Id = v.UserId <<<<<<<<< join predicate (u = v)
AND u.Id = '85597
Just STOP using commas between table names.'That simple step will force you to more carefully consider the joins.
Move the join predicates to the table they refer to AFTER an ON. (Join predicates refer to different tables either side of an operator such as equals.)
SELECT
vt.name
, u.DisplayName
FROM VoteTypes vt
, Votes v ON vt.Id = v.VoteTypeId
, Users u ON u.Id = v.UserId
WHERE vt.Id = 5
AND
AND
AND u.Id = '85597'
Replace those dreaded commas with appropriate join type, and tidy-up.
SELECT
vt.name
, u.DisplayName
FROM VoteTypes vt
INNER JOIN Votes v ON vt.Id = v.VoteTypeId
INNER JOIN Users u ON u.Id = v.UserId
WHERE vt.Id = 5
AND u.Id = '85597'
Done.
If your course is using old syntax; consider getting a better course.

Many to many query with a count of condition > 0

I have 3 tables:
Emails
Foo
EmailFoos (The many to many join table)
Foo can be complete or not.
I need to find the set of emails where the count of completed foos > 0 (and the inverse, but I can probably do that ;)
I tried something like:
SELECT e.id, e.address, count(l.foo_id) as foo_count
FROM emails e
LEFT JOIN (
SELECT l.foo_id, l.email_id
FROM foo_emails l
JOIN foos f ON (l.foo_id = f.id AND f.status = 'complete')) l ON
(l.email_id = e.id)
GROUP BY e.id
HAVING foo_count > 0;
But it keeps telling me that foo_count does not exist. My SQL_FU is weak. Postgress is the DBMS. Any help is much appreciated.
I'm pretty sure you just need to replace the foo_count in the having with count(l.foo_id).

How to convert multiple SQL left joins to Linq-To-SQL

I have a user table, a user_items table, a user_to_group table and a group table.
How would I convert the following SQL query to the correct Linq-to-sql query?
select user.username, user.email, user_items.item_number, item_types.desc, [group].name from user
left join user_items on user.user_id = user_items.user_id
left join item_types on user_items.item_type_id = item_types.item_type_id
left join user_to_group on user.user_id = user_to_group.user_id
left join [group] on user_to_group.group_id = [group].group_id
I have tried using group joins and joining with DefaultIfEmpty, but I'm unable to return the exact same results as my SQL query.
Thank you.
#ChrisF,
Sure, I could break it down into:
select user.username, user.email, user_items.item_number from user
left join user_items on user.user_id = user_items.user_id
Which I have in linq2sql as:
var users = (from u in db.users
join ui in db.user_items on u.user_id equals ui.user_id into useritems from ui in useritems.DefaultIfEmpty()
select new { user = u, item_number = useritems == null ? string.Empty : useritems.FirstOrDefault().item_number});
However, it still doesn't return all the results it should, and I can't see where I'm going wrong.
You will need to look at the join ... into ... construct.
Here is an example on MSDN
... Something else to consider ...
LINQ will allow you to turn your simple table structure into a complex hierarchy. Another option beyond the left joins would be nested queries. Maybe something like this...
var selected = from user in users
select new
{
user,
items = from item in user_items
where item.user_id == user.user_id
join it in item_types
on item.item_type_id equals it.item_type_id
select it,
groups = from ug in user_to_groups
where ug.user_id == user.user_id
join #group in groups
on ug.group_id equals #group.group_id
select #group.name,
};
I found my problem, I was selecting
useritems.FirstOrDefault().item_number
Which is what I selected into (and FirstOrDefault!), instead of what I used for my join:
ui.item_number
So my complete linq query is
var users = (from u in db.users
join ug in db.user_to_groups on p.user_id equals pg.user_id into pgrp
from ug in pgrp.DefaultIfEmpty()
join g in db.groups on pg.group_id equals g.group_id into groups
from g in groups.DefaultIfEmpty()
join ui in db.user_items on u.user_id equals ui.user_id into useritems
from ui in useritems.DefaultIfEmpty()
select new { user = u, item_number = ui == null ? string.Empty : ui.item_number, usergroup = g == null ? string.Empty : g.name});
Thanks for the help!
You query could be written more tersely if you define some associations between your objects:
from u in db.Users
from ug in u.User_To_Groups.DefaultIfEmpty()
let g = ug.Group
from ui in u.UserItems.DefaultIfEmpty()
select new
{
user = u,
item_number = ui == null ? string.Empty : ui.item_number,
usergroup = g == null ? string.Empty : g.name
});

LEFT OUTER JOIN in Linq - How to Force

I have a LEFT OUTER OUTER join in LINQ that is combining with the outer join condition and not providing the desired results. It is basically limiting my LEFT side result with this combination. Here is the LINQ and resulting SQL. What I'd like is for "AND ([t2].[EligEnd] = #p0" in the LINQ query to not bew part of the join condition but rather a subquery to filter results BEFORE the join.
Thanks in advance (samples pulled from LINQPad) -
Doug
(from l in Users
join mr in (from mri in vwMETRemotes where met.EligEnd == Convert.ToDateTime("2009-10-31") select mri) on l.Mahcpid equals mr.Mahcpid into lo
from g in lo.DefaultIfEmpty()
orderby l.LastName, l.FirstName
where l.LastName.StartsWith("smith") && l.DeletedDate == null
select g)
Here is the resulting SQL
-- Region Parameters
DECLARE #p0 DateTime = '2009-10-31 00:00:00.000'
DECLARE #p1 NVarChar(6) = 'smith%'
-- EndRegion
SELECT [t2].[test], [t2].[MAHCPID] AS [Mahcpid], [t2].[FirstName], [t2].[LastName], [t2].[Gender], [t2].[Address1], [t2].[Address2], [t2].[City], [t2].[State] AS [State], [t2].[ZipCode], [t2].[Email], [t2].[EligStart], [t2].[EligEnd], [t2].[Dependent], [t2].[DateOfBirth], [t2].[ID], [t2].[MiddleInit], [t2].[Age], [t2].[SSN] AS [Ssn], [t2].[County], [t2].[HomePhone], [t2].[EmpGroupID], [t2].[PopulationIdentifier]
FROM [dbo].[User] AS [t0]
LEFT OUTER JOIN (
SELECT 1 AS [test], [t1].[MAHCPID], [t1].[FirstName], [t1].[LastName], [t1].[Gender], [t1].[Address1], [t1].[Address2], [t1].[City], [t1].[State], [t1].[ZipCode], [t1].[Email], [t1].[EligStart], [t1].[EligEnd], [t1].[Dependent], [t1].[DateOfBirth], [t1].[ID], [t1].[MiddleInit], [t1].[Age], [t1].[SSN], [t1].[County], [t1].[HomePhone], [t1].[EmpGroupID], [t1].[PopulationIdentifier]
FROM [dbo].[vwMETRemote] AS [t1]
) AS [t2] ON ([t0].[MAHCPID] = [t2].[MAHCPID]) AND ([t2].[EligEnd] = #p0)
WHERE ([t0].[LastName] LIKE #p1) AND ([t0].[DeletedDate] IS NULL)
ORDER BY [t0].[LastName], [t0].[FirstName]
I'm not sure if it will change the result set with "AND ([t2].[EligEnd] = #p0" as part of the subquery rather than the join condition. One thing I like to do with complex queries might help you here. I like to break them into smaller queries before combining them. The deferred execution of LINQ lets us do multiple statements with one eventual call to the database. Something like this:
var elig = from mri in vwMETRemotes
where met.EligEnd == Convert.ToDateTime("2009-10-31")
select mri;
var users = from l in Users
where l.LastName.StartsWith("smith")
where l.DeletedDate == null
var result = from l in users
join mr in elig on l.Mahcpid equals mr.Mahcpid into lo
from g in lo.DefaultIfEmpty()
orderby l.LastName, l.FirstName
select g
Breaking it down like that can make it easier to debug, and perhaps it can tell LINQ better what you intend.
Code ended up looking like this. RecodePopulation and RecordRegistration are just methods to translate values from the query.
var elig = from mri in db.MetRemote
where mri.EligEnd == Convert.ToDateTime(ConfigurationManager.AppSettings["EligibilityDate"])
orderby mri.EligEnd
select mri;
var users = from l in db.Users
where l.LastName.StartsWith(filter)
where l.DeletedDate == null
select l;
var results = (from l in users
join m in elig on l.MahcpId equals m.MAHCPID into lo
from g in lo.DefaultIfEmpty()
orderby l.LastName, l.FirstName
select new UserManage()
{
Username = l.Username,
FirstName = l.FirstName,
LastName = l.LastName,
DateOfBirth = l.DOB,
Gender = l.Gender,
Status = RecodePopulation(g.Population, l.CreatedDate),
UserId = l.Id,
WellAwardsRegistered = RecodeRegistration(l.Id, 1)
}).Distinct().OrderBy(a => a.LastName).ThenBy(n => n.FirstName).Skip((currentPage - 1) * resultsPerPage).Take(resultsPerPage);