Using comparison as alias in select for Doctrine2 - mysql

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();

Related

JOIN two SELECTs with Doctrine

I need to write this query with Doctrine. How can I write it down using QueryBuilder?
SELECT charges.id, charges.currency, charges.total_transactions,
charges.total_volume, charges.commission, refunds.total_payouts
FROM
(SELECT ...very long query...) charges
LEFT JOIN
(SELECT ...very long query...) refunds
ON charges.id = refunds.id AND charges.currency = refunds.currency
You can use Native SQL and map results to entities:
use Doctrine\ORM\Query\ResultSetMapping;
$rsm = new ResultSetMapping;
$rsm->addEntityResult('AppBundle:Charges', 'charges')
->addEntityResult('AppBundle:Refunds', 'refunds')
->addFieldResult('charges', 'id', 'id')
->addFieldResult('charges', 'currency', 'currency')
->addFieldResult('charges', 'total_transactions', 'total_transactions')
->addFieldResult('charges', 'total_volume', 'total_volume')
->addFieldResult('charges', 'commission', 'commission')
->addFieldResult('refunds', 'total_payouts', 'total_payouts')
;
$sql = "
SELECT
charges.id,
charges.currency,
charges.total_transactions,
charges.total_volume,
charges.commission,
refunds.total_payouts
FROM
(SELECT ...very long query...) charges
LEFT JOIN
(SELECT ...very long query...) refunds ON charges.id = refunds.id AND charges.currency = refunds.currency
WHERE some_field = ?
";
$query = $this->getEntityManager()->createNativeQuery($sql, $rsm);
$query->setParameter(1, $name);
$entities = $query->getResult();
You can use DQL like this:
$dql = "SELECT ...";
$q = $entityManager->createQuery($dql)->setParameters($arrayParameters);
$result = $q->execute();
or QueryBuilder for each sub-query, like:
// subquery 1
$subQuery1 = $entityManager->createQueryBuilder()
->select('...')
->from('...')
->getDQL()
;
// subquery 2
$subQuery2 = ...
// etc
// ...
// main query
$query = $entityManager->createQueryBuilder()
->select('...')
->from('...', $subQuery1)
->leftJoin('...', $subQuery1->getDQL()),
->where()
;
PS: I just try provide gist for you... hope now you have clue...
Now I found out that it's impossible.
Comment created by stof:
DQL is about querying objects. Supporting subselects in the FROM clause means that the DQL parser is not able to build the result set mapping anymore (as the fields returned by the subquery may not match the object anymore).
This is why it cannot be supported (supporting it only for the case you run the query without the hydration is a no-go IMO as it would mean that the query parsing needs to be dependant of the execution mode).
In your case, the best solution is probably to run a SQL query instead (as you are getting a scalar, you don't need the ORM hydration anyway)
Source: https://github.com/doctrine/doctrine2/issues/3542

using if statement in mysql query

I would like to use if statement in sql query :
what I want :
if(tractions_delivery.send_date_id !=0 ){
date_send_commodities.id = tractions_delivery.send_date_id
}
my query :
from
tractions_delivery,user_address,province,city,date_send_commodities,users
WHERE
tractions_delivery.tr_id = $tr_id
AND
tractions_delivery.address_id = user_address.id
AND
user_address.province_id = province.id
AND
user_address.city_id = city.id
AND
//not work
(tractions_delivery.send_date_id IS NOT 0 date_send_commodities.id = tractions_delivery.send_date_id)
AND
users.id = user_address.user_id
You could use the CASE-statement
SELECT
*
FROM
tractions_delivery,
user_address,
province,
city,
date_send_commodities,users
WHERE
tractions_delivery.tr_id = $tr_id AND
tractions_delivery.address_id = user_address.id AND
user_address.province_id = province.id AND
user_address.city_id = city.id AND
CASE WHEN tractions_delivery.send_date_id != 0 THEN date_send_commodities.id = tractions_delivery.send_date_id ELSE 1=1 END AND
users.id = user_address.user_id
You can only use if statements in stored procedures or functions. If you just write a sql statement unfortunately you cannot use if statements around the query. But you can use logic in the query itself, e.g.:
SELECT CASE WHEN col1 = col2 THEN'col1 equals col2' else 'col1 doesnt equal col2' ELSE
FROM table1
So around doesnt work, but in the field list you can create CASE WHEN ELSE END logic.
CASE or IF() operators can be of help.
Examples,
SELECT (CASE 1 WHEN 1 THEN 'One' WHEN 2 THEN 'Two' ELSE 'More' END) 'Result';
OR
SELECT IF(1=1, 'One', 'Two') 'Result';
These CASE and IF() operators can be used in the SELECT clause to conditionally interpret column values and return in the resultset.
Note: Do not confuse CASE operator here with 'CASE conditional syntax block' that ends with END CASE.

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.

Custom orderby in 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