Custom orderby in linq to sql - linq-to-sql

I've already searched the archives but can't find a solution that works for linq to sql.
How do you create a custom orderby in linq to sql so that it generates SQL code like this
ORDER BY
CASE SEASON
WHEN 'WINTER' THEN 1
WHEN 'SPRING' THEN 2
WHEN 'SUMMER' THEN 3
WHEN 'AUTUMN' THEN 4
END
Note that custom comparators dont seem to compile and OrderByWeight as seen in this tutorial (http://www.skindog.co.uk/2009/03/18/custom-sorting-order-in-linq-order-by-weighting/) doesn't seem to exist
Note
I want the ordering to happen on the sql server and not in c# as this will give me different results since I am partitioning my results.

Here is an approach using a lambda expression
MyTable
.OrderBy (t => (t.Season == "Winter") ? 1 : (t.Season == "Spring") ? 2 : [...])
.Select (
t => new
{
MyColumn = t.MyColumn
...
}
)

You must select your data first in an inner loop like you did, then select data from that result and sort normally on your custom column:
(off my head)
from s in
(from x in y select new { Sort = x.z == 'WINTER' ? 1 : x.z == 'SPRING' ? 2 : [...], Data = x })
orderby s.Sort
select s.Data
Something like that
Hope this helps

Related

Laravel 4 - SQL query to Laravel Eloquent query

I'm working on a school project and I'm trying to get a query working.
SELECT *
FROM `ziekmeldingen` AS a
WHERE NOT EXISTS
(SELECT *
FROM `ziekmeldingen` AS b
WHERE `ziek` = 1
AND a.personell_id = b.personell_id)
Name of the model: ZiekmeldingenModel
I tried 2 things, both dont work ->
$medewerkers = ZiekmeldingenModel::whereNotExists(function($query)
{
$query->select()->from('ziekmeldingen AS b')->where('ziek', '=', '1')->where('ziekmeldingen.personell_id', '=', 'b.personell_id');
})->get();
return $medewerkers;
And
$medewerkers = ZiekmeldingenModel::raw('SELECT * FROM `ziekmeldingen` as a WHERE NOT EXISTS ( SELECT * FROM `ziekmeldingen` as b WHERE `ziek` = 1 AND a.personell_id = b.personell_id)')->get();
Both of them give back all the results from the table while it should only give back 1 result (I've tested the original query, it works).
EDIT: Forgot to mention I'm using relationships in the model. So the raw solution probably won't work anyway
Found the answer. Had to use a combo of both the things I tried.
$medewerkers = ZiekmeldingenModel::select()
->from(DB::raw('`ziekmeldingen` AS a'))
->whereNotExists(function($query){
$query->select()
->from(DB::raw('`ziekmeldingen` AS b'))
->whereRaw('`ziek` = 1 AND a.personell_id = b.personell_id');
})->get();
return $medewerkers;
Thanks for any help and effort.
Definitely no need for select(). Also no raw in from or whereRaw needed.
The only unusual thing here is raw piece in the where, since you don't want table.field to be bound and treated as string. Also, you can use whereRaw for the whole clause in case you have your tables prefixed, otherwise you would end up with something like DB_PREFIX_a.personell_id, so obviously wrong.
This is how you do it:
$medewerkers = ZiekmeldingenModel::from('ziekmeldingen AS a')
->whereNotExists(function ($q) {
$q->from('ziekmeldingen AS b')
->where('ziek', 1)
->where('a.personell_id', DB::raw('b.personell_id'))
// or:
// ->whereRaw('a.personell_id = b.personell_id');
})->get();
Use the take() method though if you're not ordering your results the record you get back could be any of the results.
$medewerkers = ZiekmeldingenModel::raw('SELECT * FROM `ziekmeldingen` as a WHERE NOT EXISTS ( SELECT * FROM `ziekmeldingen` as b WHERE `ziek` = 1 AND a.personell_id = b.personell_id)')->take(1)->get();

IF condition in mysql

I have a contact table I wish to query when a certain condition exists. I tried the query below but am getting a syntax error.
SELECT *
FROM contact_details
WHERE contactDeleted` =0
AND IF ( contactVisibility = "private"
, SELECT * FROM contact_details
WHERE contactUserId = 1
, IF( contactVisibility = "group"
, SELECT * FROM contact_details
WHERE contactGroup = 3
)
)
If I'm understanding your question correctly (which is difficult with the lack of info you've provided. Sample datasets and expected outcomes are typically helpful), then I don't believe you need IFs at all for what you want. The following will return contacts that are not deleted and who either have (visibility = "private" and userId = 1) OR (visibility = "group" and group = 3)
SELECT *
FROM contact_details
WHERE contactDeleted = 0
AND (
(contactVisibility = "public")
OR
(contactVisibility = "private" AND contactUserId = 1)
OR
(contactVisibility = "group" AND contactGroup = 3)
)
I am assuming you want to use the IF() function and not the statement which is for stored functions..
Refer to this link for more information on that.
Notice that you have put 2 select statements in there, where the custom return values are supposed to be. So you are returning a SELECT *... now notice that in your upper level sql statement you have an AND.. so you basically writing AND SELECT *.. which will give you the syntax error.
Try using .. AND x IN (SELECT *) .. to find if x is in the returned values.
Let me also list this link to make use of an existing and well written answer which may also applicable to your question.

Using comparison as alias in select for Doctrine2

Trying to do this in Doctrine2:
...->createQuery('SELECT m.id, (m.status != 1) as verified...
But that throws an error - if I take parenthesis off I get another error. How do I achieve this m.status comparison?
Thanks
Doctrine 2 doesn't support these comparisons in the SELECT clause (at least not up to 2.3, not sure about 2.4).
You can use a CASE expression as workaround:
SELECT m.id, CASE WHEN m.status != 1 THEN 1 ELSE 0 END AS verified ...
or:
SELECT m.id, CASE WHEN m.status = 1 THEN 0 ELSE 1 END AS verified ...
If you need verified for an ORDER BY clause (or something like that), but don't actually need it in the result, you can use the HIDDEN expression:
SELECT m.id, CASE WHEN m.status = 1 THEN 0 ELSE 1 END AS HIDDEN verified ...
A completely different solution is to write a custom DQL function.
You can use the solution proposed here: Cumulative DQL with Doctrine
When working with entities, keep in mind that adding selects will make the query return an array for each result:
$res = $em->createQueryBuilder()
->from('BlogPost', 'p')
->select('p')
->addSelect('(2+3) AS dummy')
->getQuery()->getResult();
Iterating over $res will return an array:
foreach($res as $mixed){
echo get_class($mixed[0]); //$mixed[0] contains the BlogPost
echo $mixed['dummy']; //displays the dummy result (5)
}
check this out: 13.2.4. Using Expr* classes to create conditionals
using Expression methods you could do something like:
$qb = $this->entityManager->createQueryBuilder();
$query = $qb->select('m.id')
->from('Entities\MyEntity', 'm')
/*neq() is the "not equal" comparison function*/
->where($qb->expr()->neq('m.status', $someValue)),
->getQuery();

LINQ to SQL generates negative conditions in WHERE clause

I am using LINQ to SQL to retrieve data, using boolean conditions (BIT columns in SQL). My LINQ query looks something like this:
var query = from r in db.Requests
select r;
query = query.Where(r => r.Completed == someBooleanVal);
query = query.Where(r => r.Cancelled == someOtherBool);
return query.ToList();
The 'Where()' gets applied in a different method, that's why I'm putting it in separately.
When the boolean values are given as false, the generated SQL looks something like this:
SELECT [t0].[col1], [t0].[col2], [t0].[col3], [t0].[etc]
FROM [dbo].[Requests] AS [t0]
WHERE (NOT(([t0].[Cancelled]) = 1) AND (NOT(([t0].[Completed]) = 1)
in stead of what I would use:
WHERE [t0].[Cancelled] = 0 AND [t0].[Completed] = 0
This runs very, very slowly. I strongly suspect that it is because of the negative conditions on the boolean values it generated (all the selected columns are covered by an index, and the two columns in the where clause have a separate index on them).
Why is it generating negative conditions? How can I fix it?
var query =
from r in db.Requests.Where(r => r.Completed == someBooleanVal && r.Cancelled == someOtherBool)
select r;
return query.ToList();
Hope it can help you and have a nice day.

Entity Framework - MySQL - Null Comparison!

Whats wrong with following code? :(
int? parentFolderId = null;
if( this.Request.QueryString ["folderId"] != null )
parentFolderId = Convert.ToInt32( this.Request.QueryString ["folderId"] );
f = ( from x in this.EntityDataContext.folders
where x.parent_id == parentFolderId
select x ).ToList();
It returns nothing! Though there ARE records in database with parent_id as NULL.
However, when I explicitly state NULL; it works!
f = ( from x in this.EntityDataContext.folders
where x.parent_id == null
select x ).ToList();
What could be the issue?
PS: I hate working with mysql using Entity Framework .... every damn simple thing has million issues!
Long Shot
f = ( from x in this.EntityDataContext.folders
where ((parentFolderId!=null && x.parent_id == parentFolderId)
||(parentFolderId==null && x.parent_id == null))
select x ).ToList();
Yeah, this seams wired, and I guess your first example should work just fine with MsSql.
Maybe it's time to file a bug to authors of Linq to MySql ?
I had this kind of problem in sql server and in sql server the generated query looks like "parent_id = null" when you are working on a nullable field. And that query returns nothing even parent_id is null.
The tricky way in here is, you should force EF to create a query like "parent_id is null" and the code I tried in linq was;
if(parentFolderId.HasValue)
{
f = ( from x in this.EntityDataContext.folders
where x.parent_id == parentFolderId
select x ).ToList();
}
else
{
f = ( from x in this.EntityDataContext.folders
where !x.parent_id.HasValue
select x ).ToList();
}
I know this does not seem a perfect way to do this but, this is how I could get rid of that issue.
You'll probably find there's an issue involving using DBNull or something similar. I would think that in the second case (where you explicitly state "null") that Linq is automatically transforming it to DBNull in the background.
perhaps try something along the lines of:
where x.parent_id == ( parentFolderId == null ? DBNull.Value : parentFolderId )
Hope that puts you on the right track!
This is connector bug and I have reported at mysql.