NHIbernate: Setting up subquery to use property value from outer query - nhibernate

I have the following sub/criteria:
var sq = DetachedCriteria.For<Title>()
.CreateAlias("Genres", "genre")
.Add(Restrictions.IsNull("genre.ParentId"))
.SetProjection(Projections.Property<Genre>(g=>g.Name));
var q =
session.CreateCriteria(typeof(Title))
.SetProjection(
Projections.Alias(Projections.SqlFunction("array", null, Projections.SubQuery(sq)), "TopLevelGenre"),
Projections.Property<Title>(t1=>t1.Id)
)
.SetMaxResults(5);
Which results in the following SQL query:
SELECT array((SELECT this_0_.title as y0_
FROM title this_0_
inner join title_genre genres3_
on this_0_.title_id = genres3_.title_id
inner join genre genre1_
on genres3_.genre_id = genre1_.genre_id
WHERE genre1_.parent_id is null)) as y0_,
this_.title_id as y1_
FROM title this_
limit 5 /* :p1 */
How do I set it up so that my subquery uses the value of a property from the outer query? For example, I'd like for the subquery to filter by the title_id value. Is there anything in NHibernate that allows me to project a property value to the subquery?
Thanks!

Turns out I was close. All I had to do was create an alias for Title and use that in the Where clause of my subquery.
Title title = null;
c = Session
.QueryOver(() => title)
....
.SelectList(list => list
.Select(Projections.Alias(Projections.SqlFunction("array", null, Projections.SubQuery(sq.Where(tt => tt.Id == title.Id))), "TopLevelGenre"))
);
Hope that helps someone..

Related

SQL query to get the author who having maximum number of post (custom post type) in Wordpress

I would like to get the author information based on a particular criteria. The criteria is that, would like to get the author who having maximum number of post(custom post type).
This is the code I am trying to get the result.
$author_query = new WP_User_Query(array (
'orderby' => 'post_count',
'order' => 'DESC',
));
$authors = $author_query->get_results();
foreach ( $authors as $author ) {
echo $author->ID;
echo $author->display_name;
}
I solved this using custom sql query. Posting the answer for others who need it in the future.
SELECT SQL_CALC_FOUND_ROWS wp_users.ID,post_count FROM wp_users RIGHT JOIN (SELECT post_author, COUNT(*) as post_count FROM wp_posts WHERE ( ( post_type = 'custom-post-type' AND ( post_status = 'publish' ) ) ) GROUP BY post_author) p ON (wp_users.ID = p.post_author) WHERE 1=1 ORDER BY post_count DESC

Linq to sql - Join 2 tables, select 1 row from right table with a 1 to many relationship

I am trying to select the forum categories and the last post in each respective category. I have been able to accomplish this in SQL using OUTER APPLY, but haven't been able to successfully convert this to LINQ.
Produces the desired result in SQL:
SELECT fc.CategoryID, fc.CategoryName, fc.PostCount, ft.Title, ft.LastPost, ft.LastPostId, ft.TopicId
FROM ForumCategory AS fc
OUTER APPLY
(
SELECT TOP (1) *
FROM ForumTopic
WHERE ForumTopic.CategoryID = fc.CategoryID
ORDER BY ForumTopic.lastpost DESC
) ft
My attempt at converting to LINQ:
Dim query = From fc In ctx.ForumCategories _
Join ft In ctx.ForumTopics On fc.CategoryID Equals ft.CategoryID _
Select New With {
fc.CategoryID,
fc.CategoryName,
fc.PostCount,
ft.Title,
ft.LastPostId,
ft.LastPost.OrderByDescending().First()
}
I am getting an error stating: 'OrderByDescending' is not a member of 'Date?'
You write it as follows:
var q = from fc in ctx.ForumCategories
from ft in (from x in ctx.ForumTopic
where x.CategoryID == fc.CategoryID
order by x.lastpost desc
select new
{
x.Title,
x.LastPost,
x.LastPostId,
x.TopicId
}).Take(1).DefaultIfEmpty()
select new
{
fc.CategoryID,
fc.CategoryName,
fc.PostCount,
ft.Title,
ft.LastPost,
ft.LastPostId,
ft.TopicId
};

Column is invalid in the ORDER BY clause because it is not contained in either an aggregate function or the GROUP BY clause

Ok here's my View (vw_LiftEquip)
SELECT dbo.tbl_equip_swl_unit.unit_id,
dbo.tbl_equip_swl_unit.unit_name,
dbo.tbl_equip_swl_unit.archived,
dbo.tbl_categories.category_id,
dbo.tbl_categories.categoryName,
dbo.tbl_categories.parentCategory,
dbo.tbl_categories.sub_category,
dbo.tbl_categories.desc_category,
dbo.tbl_categories.description,
dbo.tbl_categories.miscellaneous,
dbo.tbl_categories.category_archived,
dbo.tbl_equip_swl_unit.unit_name AS Expr1,
dbo.tbl_categories.categoryName AS Expr2,
dbo.tbl_categories.description AS Expr3,
dbo.tbl_equip_depts.dept_name,
dbo.tbl_equip_man.man_name,
dbo.tbl_Lifting_Gear.e_defects AS Expr7,
dbo.tbl_Lifting_Gear.e_defects_desc AS Expr8,
dbo.tbl_Lifting_Gear.e_defects_date AS Expr9,
dbo.tbl_equipment.equipment_id,
dbo.tbl_equipment.e_contract_no,
dbo.tbl_equipment.slID,
dbo.tbl_equipment.e_entered_by,
dbo.tbl_equipment.e_serial,
dbo.tbl_equipment.e_model,
dbo.tbl_equipment.e_description,
dbo.tbl_equipment.e_location_id,
dbo.tbl_equipment.e_owner_id,
dbo.tbl_equipment.e_department_id,
dbo.tbl_equipment.e_manafacture_id,
dbo.tbl_equipment.e_manDate1,
dbo.tbl_equipment.e_manDate2,
dbo.tbl_equipment.e_manDate3,
dbo.tbl_equipment.e_dimensions,
dbo.tbl_equipment.e_test_no,
dbo.tbl_equipment.e_firstDate1,
dbo.tbl_equipment.e_firstDate2,
dbo.tbl_equipment.e_firstDate3,
dbo.tbl_equipment.e_prevDate1,
dbo.tbl_equipment.e_prevDate2,
dbo.tbl_equipment.e_prevDate3,
dbo.tbl_equipment.e_insp_frequency,
dbo.tbl_equipment.e_swl,
dbo.tbl_equipment.e_swl_unit_id,
dbo.tbl_equipment.e_swl_notes,
dbo.tbl_equipment.e_cat_id,
dbo.tbl_equipment.e_sub_id,
dbo.tbl_equipment.e_parent_id,
dbo.tbl_equipment.e_last_inspector,
dbo.tbl_equipment.e_last_company,
dbo.tbl_equipment.e_deleted AS Expr11,
dbo.tbl_equipment.e_deleted_desc AS Expr12,
dbo.tbl_equipment.e_deleted_date AS Expr13,
dbo.tbl_equipment.e_deleted_insp AS Expr14,
dbo.tbl_Lifting_Gear.e_defects_action AS Expr15,
dbo.tbl_equipment.e_rig_location,
dbo.tbl_Lifting_Gear.e_add_type AS Expr17,
dbo.tbl_Lifting_Gear.con_id,
dbo.tbl_Lifting_Gear.lifting_date,
dbo.tbl_Lifting_Gear.lifting_ref_no,
dbo.tbl_Lifting_Gear.e_id,
dbo.tbl_Lifting_Gear.inspector_id,
dbo.tbl_Lifting_Gear.lift_testCert,
dbo.tbl_Lifting_Gear.lift_rig_location,
dbo.tbl_Lifting_Gear.inspected,
dbo.tbl_Lifting_Gear.lifting_through,
dbo.tbl_Lifting_Gear.liftingNDT,
dbo.tbl_Lifting_Gear.liftingTest,
dbo.tbl_Lifting_Gear.e_defects,
dbo.tbl_Lifting_Gear.e_defects_desc,
dbo.tbl_Lifting_Gear.e_defects_date,
dbo.tbl_Lifting_Gear.e_defects_action,
dbo.tbl_Lifting_Gear.lift_department_id,
dbo.tbl_Lifting_Gear.lifting_loc
FROM dbo.tbl_equipment
INNER JOIN dbo.tbl_equip_swl_unit
ON dbo.tbl_equipment.e_swl_unit_id = dbo.tbl_equip_swl_unit.unit_id
INNER JOIN dbo.tbl_categories
ON dbo.tbl_equipment.e_cat_id = dbo.tbl_categories.category_id
INNER JOIN dbo.tbl_equip_depts
ON dbo.tbl_equipment.e_department_id = dbo.tbl_equip_depts.dept_id
INNER JOIN dbo.tbl_equip_man
ON dbo.tbl_equipment.e_manafacture_id = dbo.tbl_equip_man.man_id
INNER JOIN dbo.vwSubCategory
ON dbo.tbl_equipment.e_sub_id = dbo.vwSubCategory.category_id
INNER JOIN dbo.vwDescCategory
ON dbo.tbl_equipment.e_cat_id = dbo.vwDescCategory.category_id
INNER JOIN dbo.tbl_Lifting_Gear
ON dbo.tbl_equipment.equipment_id = dbo.tbl_Lifting_Gear.e_id
And here's the select statement with subquery that I am using:
SELECT *
FROM vw_LiftEquip
WHERE lifting_loc = ? AND
con_id = ? AND
EXPR11 =
'N'(
SELECT MAX(lifting_date) AS maxLift
FROM vw_LiftEquip
WHERE e_id = equipment_id
)
ORDER BY lifting_ref_no,
category_id,
e_swl,
e_serial
I get the error :
Column "vw_LiftEquip.category_id" is invalid in the ORDER BY clause because it is not contained in either an aggregate function or the GROUP BY clause.
Can't see why its returning that error, this is admittedly the first time I've ran a subquery on such a complex view, and I am a bit lost, thanks in advance for any help. I have looked through the similar posts and can find no answers to this one, sorry if I am just being dumb.
You are missing AND between EXPR11 = 'N' and (SELECT MAX(...
Otherwise, it looks OK. MAX without GROUP BY is allowed if you have no other columns in the SELECT
Update: #hvd also noted that you have nothing to compare to MAX(lifting_date). See comment
Update 2,
SELECT *
FROM vw_LiftEquip v1
CROSS JOIN
(
SELECT MAX(lifting_date) AS maxLift
FROM vw_LiftEquip
WHERE e_id = equipment_id
) v2
WHERE v1.lifting_loc = ? AND
v1.con_id = ? AND
v1.EXPR11 = 'N'
ORDER BY v1.lifting_ref_no,
v1.category_id,
v1.e_swl,
v1.e_serial

Double LEFT JOIN

I want to receive property name and units count and specails count. I have this query:
SELECT
`property`.`property_name`,
COUNT(unit_id) AS `units_count`,
COUNT(special_id) AS `specials_count`
FROM `property`
LEFT JOIN `property_unit` ON unit_property_id = property_id
LEFT JOIN `property_special` ON special_property_id = property_id
WHERE (property_id = '1')
GROUP BY `property_id`
ORDER BY `property_name` ASC
But it is not working properly. If I have one of these left joins - it's ok, but if I have two, I get this result:
["property_name"] => string(11) "Rivers Edge"
["units_count"] => string(1) "2"
["specials_count"] => string(1) "2"
Specials count is 2 and units_count is 2, but units count is really '1'. How can I get correct counts for it?
P.S: for those who know Zend Framework:
$select->setIntegrityCheck(FALSE)
->from(
'property',
array(
'property_name',
)
)
->joinLeft(
'property_unit',
'unit_property_id = property_id',
array(
'units_count' => 'COUNT(unit_id)'
)
)
->joinLeft(
'property_special',
'special_property_id = property_id',
array(
'specials_count' => 'COUNT(special_id)'
)
)
->group('property_id')
->order('property_name');
Try this:
SELECT
`property`.`property_name`,
COUNT(distinct unit_id) AS `units_count`,
COUNT(distinct special_id) AS `specials_count`
FROM `property`
LEFT JOIN `property_unit` ON unit_property_id = property_id
LEFT JOIN `property_special` ON special_property_id = property_id
WHERE (property_id = '1')
GROUP BY `property_id`
ORDER BY `property_name` ASC
EDIT:
You shouldn't always use distinct - it happens to be the right option in this case.
select count(fieldname) returns the number of times that fieldname is not null; select count(distinct fieldname) returns the number of distinct values of fieldname.
In the original query, property_unit and property_special aren't joined to each other, only to property - so for a single property that had 5 units and 7 specials, 35 rows would be returned; therefore count(unit_id) and count(special_id) would both return 35. Since there would be 5 distinct values of unit_id and 7 distinct values of special_id (because these fields uniquely identify their records), count(distinct ...) returns the correct values in these circumstances.
Your SQL should be something like this:
SELECT
`property`.`property_name`,
COUNT(property_unit.unit_id) AS `units_count`,
COUNT(property_special.special_id) AS `specials_count`
FROM `property`
LEFT JOIN `property_unit` ON (property_unit.unit_property_id = property.property_id)
LEFT JOIN `property_special` ON (property_special.special_property_id = property.property_id)
WHERE (property.property_id = '1')
GROUP BY `property.property_id`
ORDER BY `property.property_name` ASC

LINQ 2 SQL: top 1 post per member ordered by created data

Okay so I have the sql to work this out as asked in the stackoverflow question here.
Does anyone know how to translate this to linq 2 sql? I'm guessing that the easiest way is to add a stored procedure, but I am curious to see if it can be linq-a-fied :P
select p.*
from post p join
(
select memberId, max(createdDate) as maxd
from post
group by memberId
) as p2 on p.memberid = p2.memberid and p.createdDate=p2.maxd
order by p.createdDate desc
I'm not totally sure this is the most efficient way to run this query (maybe it is, but I've got a feeling there's a better way. Haven't thought of it yet).
from
post in Nt_Post
join
memberdates in (
from
p_inner in Nt_Post
group
p_inner by p_inner.MemberId into grouped
select new {
MemberId = grouped.Key,
ActivationDate = grouped.Max(m => m.ActivationDate)
})
on
new { post.MemberId, post.ActivationDate }
equals
new { memberdates.MemberId, memberdates.ActivationDate }
orderby post.ActivationDate
select post;
Here is the query working within LinqPad on my database (not createdDate is actually activationDate and the Post table is Nt_Post. Thanks to Rex M for commming up with the solution :P
var q =
from
post in Nt_Post
join
memberdates in (
from
p_inner in Nt_Post
group
p_inner by p_inner.MemberId into grouped
select new {
MemberId = grouped.Key,
ActivationDate = grouped.Max(m => m.ActivationDate)
})
on
new { post.MemberId, post.ActivationDate }
equals
new { memberdates.MemberId, memberdates.ActivationDate }
orderby post.ActivationDate
select post;
q.Dump();
The sql generated is:
SELECT [t0].[Id], [t0].[Title], [t0].[Teaser], [t0].[Text], [t0].[ActivationDate], [t0].[CreatedDate], [t0].[LastModifiedDate], [t0].[IsActive], [t0].[Permalink], [t0].[MemberId], [t0].[HomePageVisibility], [t0].[Image], [t0].[ImageContentType], [t0].[HasNotifiedRTR]
FROM [nt_Post] AS [t0]
INNER JOIN (
SELECT MAX([t1].[ActivationDate]) AS [value], [t1].[MemberId]
FROM [nt_Post] AS [t1]
GROUP BY [t1].[MemberId]
) AS [t2] ON ([t0].[MemberId] = [t2].[MemberId]) AND ([t0].[ActivationDate] = [t2].[value])
ORDER BY [t0].[ActivationDate]