Complicate leftjoin conditions using eloquent ORM - laravel-4

I have a complicated query, not able to write it using eloquent
SELECT *
FROM all_reports
LEFT JOIN activity_logs AS AL ON (all_reports.id = AL.type_id
AND (AL.user_id =
OR AL.user_id IS NULL))
Please help with the above query.
Thanks :)

Related

Conver MySQL query with LEFT statment to Laravel Eloquent

Could anybody help to translate below query to Laravel Eloquent syntactics.
SELECT LEFT(subject , 10) FROM tbl
Thanks.
on the top of your Class, Call this
use DB;
then type this as your query
DB::table('tbl')->select('LEFT(subject , 10)')->get();

Eloquent query alternative

How can I write the following in Laravel's Eloquent?
SELECT *
FROM
( SELECT real_estate.property_id,
real_estate.amount_offered,
payee.summa
FROM real_estate
LEFT JOIN
(SELECT property_id,
SUM(amount) AS summa
FROM payments
GROUP BY property_id) payee ON payee.property_id = real_estate.property_id ) yoot
WHERE summa = 0.05 * amount_offered
Been on this for a while now and really can't get around it. Lemme explain the whole cause for the panic.
I have two tables, one for property and another for payments made on those properties. Now at any given time I will like to query for what properties have been paid for to a certain percentage hence the 0.05 which reps 5%. As it is the query works but I need an Eloquent alternative for it. Thanks
Anywhere you have subqueries in your SQL you'll need to use DB::raw with Eloquent. In this case you have a big subquery for the FROM statement, so the easiest way would be to do this:
DB::table(
DB::raw('SELECT real_estate.property_id, real_estate.amount_offered, payee.summa FROM real_estate LEFT JOIN (SELECT property_id, SUM(amount) AS summa FROM payments GROUP BY property_id) payee ON payee.property_id = real_estate.property_id)')
)
->where('summa', DB::raw('0.05 * amount_offered'))->get();
Notice I used DB::raw for the WHERE statment value as well. That's because you are doing a multiplication using a column name, and the value would otherwise be quoted as a string.
If you want to go a step further and build each subquery using Eloquent, then convert it to an SQL string and injecting it using DB::raw, you can do this:
$joinQuery = DB::table('payments')
->select('property_id', 'SUM(amount) AS summa')
->groupBy('property_id')
->toSql();
$tableQuery = DB::table('real_estate')
->select('real_estate.property_id', 'real_estate.amount_offered', 'payee.summa')
->leftJoin(DB::raw('(' . $joinQuery . ')'), function ($join)
{
$join->on('payee.property_id', '=', 'real_estate.property_id');
})
->toSql();
DB::table(DB::raw('(' . $tableQuery . ')'))->where('summa', DB::raw('0.05 * amount_offered'))->get();
In this case, the second approach doesn't have any benefits over the first, except perhaps that it's more readable. However, building subqueries using Eloquent, does have it's benefitfs when you'd need to bind any variable values to the query (such as conditions), because the query will be correctly built and escaped by Eloquent and you would not be prone to SQL injection.

How to write the following MYSQL query in criteria query and hibernate query?

How can I write the criteria query and hibernate query for the following MySQL query
SELECT * FROM (SELECT * FROM outdatadetail where algorithmno="a0025_d2" and stringno=01 ORDER BY testid desc) sub_query GROUP BY subjectid;
Any suggestions.
String sql = "SELECT * FROM (SELECT * FROM outdatadetail where algorithmno='a0025_d2' and stringno=01 ORDER BY testid desc) sub_query GROUP BY subjectid;";
Session session = getSession().getSessionFactory().getCurrentSession();
Query query = session.createSQLQuery(sql);
As far as I understand after reading the documentation and looking at examples you don't need a sub-query to do what you are trying to.
Basically you write 1 query and set a projection to do the grouping.
Criteria query = currentSession.createCriteria(OutDataDetail.class);
query.setProjection(Projections.groupProperty("subjectid").as("subjectid"));
query.add(Restrictions.eq("algorithmno", "a0025_d2"));
query.add(Restrictions.eq("stringno", "01"));
query.addOrder(Order.desc("testid"));
return query.list();
The Criteria API by itself is fairly useful. But its real power comes when you start using classes like Projection, Subqueries, Order etc. in conjunction with your Criteria.
If you want to use the Criteria API with a sub-query you can do the following:
DetachedCriteria subquery = currentSession.createCriteria(OutDataDetail.class);
subquery.add(Restrictions.eq("algorithmno", "a0025_d2"));
subquery.add(Restrictions.eq("stringno", "01"));
subquery.addOrder(Order.desc("testid"));
Criteria query = currentSession.createCriteria(OutDataDetail.class);
query.setProjection(Projections.groupProperty("subjectid").as("subjectid"));
query.add(Subqueries.exists(subquery);
return query.list();
Both implementations should return a list of OutDataDetail objects (assuming that's the object you are working with).
DISCLAIMER: I have not tried any of this. It may be that this will not work for you. This answer is written based on my knowledge of working with the Criteria API and its associated classes in the past, and the Hibernate 4.1 Manual. You can see the manual section on Projections and grouping here.

Unable to use order by in sub query in HQL

I have this HQL where I need a subquery. I know it's not legal to make a subquery in order by, but I can't figure out how to do it
SELECT OBJECT(l) FROM InboundNotification l
INNER JOIN l.item item
WHERE l.job = ? ORDER BY (SELECT SUM(itemInst.qty)
FROM ItemInst itemInst
WHERE itemInst.receivedFromNotification_id = l.id) DESC, item.localId DESC
The above fails since I have the subquery in order by. How can I reconfigure it so this will work?
A sort in the Java code is not a option here even though it's almost as efficient.
ok, i haven't a notion of hql, but I'm gonna assume it's something like other query languages dive in here given that this question has remained unanswered for so long.
could you rewrite the query so it's something like this:
SELECT OBJECT(l), SUM(itemInst.qty) theSum
FROM InboundNotification l
INNER JOIN l.item item WHERE l.job = ?
INNER JOIN ItemInst on ItemInst.KEY = l.KEY
WHERE itemInst.receivedFromNotification_id = l.id)
GROUP BY OBJECT(l)
ORDER BY theSum
where ItemInst.KEY = l.KEY shows the appropriate relationship for your situation (if such a relationship exists)

Linq to entities Left Join

I want to achieve the following in Linq to Entities:
Get all Enquires that have no Application or the Application has a status != 4 (Completed)
select e.*
from Enquiry enq
left outer join Application app
on enq.enquiryid = app.enquiryid
where app.Status <> 4 or app.enquiryid is null
Has anyone done this before without using DefaultIfEmpty(), which is not supported by Linq to Entities?
I'm trying to add a filter to an IQueryable query like this:
IQueryable<Enquiry> query = Context.EnquirySet;
query = (from e in query
where e.Applications.DefaultIfEmpty()
.Where(app=>app.Status != 4).Count() >= 1
select e);
Thanks
Mark
In EF 4.0+, LEFT JOIN syntax is a little different and presents a crazy quirk:
var query = from c1 in db.Category
join c2 in db.Category on c1.CategoryID equals c2.ParentCategoryID
into ChildCategory
from cc in ChildCategory.DefaultIfEmpty()
select new CategoryObject
{
CategoryID = c1.CategoryID,
ChildName = cc.CategoryName
}
If you capture the execution of this query in SQL Server Profiler, you will see that it does indeed perform a LEFT OUTER JOIN. HOWEVER, if you have multiple LEFT JOIN ("Group Join") clauses in your Linq-to-Entity query, I have found that the self-join clause MAY actually execute as in INNER JOIN - EVEN IF THE ABOVE SYNTAX IS USED!
The resolution to that? As crazy and, according to MS, wrong as it sounds, I resolved this by changing the order of the join clauses. If the self-referencing LEFT JOIN clause was the 1st Linq Group Join, SQL Profiler reported an INNER JOIN. If the self-referencing LEFT JOIN clause was the LAST Linq Group Join, SQL Profiler reported an LEFT JOIN.
Do this:
IQueryable<Enquiry> query = Context.EnquirySet;
query = (from e in query
where (!e.Applications.Any())
|| e.Applications.Any(app => app.Status != 4)
select e);
I don't find LINQ's handling of the problem of what would be an "outer join" in SQL "goofy" at all. The key to understanding it is to think in terms of an object graph with nullable properties rather than a tabular result set.
Any() maps to EXISTS in SQL, so it's far more efficient than Count() in some cases.
Thanks guys for your help. I went for this option in the end but your solutions have helped broaden my knowledge.
IQueryable<Enquiry> query = Context.EnquirySet;
query = query.Except(from e in query
from a in e.Applications
where a.Status == 4
select e);
Because of Linq's goofy (read non-standard) way of handling outers, you have to use DefaultIfEmpty().
What you'll do is run your Linq-To-Entities query into two IEnumerables, then LEFT Join them using DefaultIfEmpty(). It may look something like:
IQueryable enq = Enquiry.Select();
IQueryable app = Application.Select();
var x = from e in enq
join a in app on e.enquiryid equals a.enquiryid
into ae
where e.Status != 4
from appEnq in ae.DefaultIfEmpty()
select e.*;
Just because you can't do it with Linq-To-Entities doesn't mean you can't do it with raw Linq.
(Note: before anyone downvotes me ... yes, I know there are more elegant ways to do this. I'm just trying to make it understandable. It's the concept that's important, right?)
Another thing to consider, if you directly reference any properties in your where clause from a left-joined group (using the into syntax) without checking for null, Entity Framework will still convert your LEFT JOIN into an INNER JOIN.
To avoid this, filter on the "from x in leftJoinedExtent" part of your query like so:
var y = from parent in thing
join child in subthing on parent.ID equals child.ParentID into childTemp
from childLJ in childTemp.Where(c => c.Visible == true).DefaultIfEmpty()
where parent.ID == 123
select new {
ParentID = parent.ID,
ChildID = childLJ.ID
};
ChildID in the anonymous type will be a nullable type and the query this generates will be a LEFT JOIN.

Resources