Laravel Eloquent where field is X or null - php

I have a table like this:
table
- field1: tinyint
- field2: varchar (nullable)
- datefield: timestamp (nullable)
Now I want to get all entries where field1 is 1, field2 is null and where datefield is smaller than X or null. I already tried something like this:
$query = Model::where('field1', 1)
->whereNull('field2')
->where('datefield', '<', $date)
->orWhereNull('datefield');
but thats not working. I always get every entry where datefield is null. It doesn't matter what the other fields are. I also tried to split it in 2 queries: First get every row where datefield is smaller than X or null and then (based on it) get every field where field1 is 1 and field2 is null.
The result was the same.
Any idea how to do this?

It sounds like you need to make use of advanced where clauses.
Given that search in field1 and field2 is constant we will leave them as is, but we are going to adjust your search in datefield a little.
Try this:
$query = Model::where('field1', 1)
->whereNull('field2')
->where(function ($query) {
$query->where('datefield', '<', $date)
->orWhereNull('datefield');
}
);
If you ever need to debug a query and see why it isn't working, it can help to see what SQL it is actually executing. You can chain ->toSql() to the end of your eloquent query to generate the SQL.

You could merge two queries together:
$merged = $query_one->merge($query_two);

Using coalesce() converts null to 0:
$query = Model::where('field1', 1)
->whereNull('field2')
->where(DB::raw('COALESCE(datefield_at,0)'), '<', $date)
;

If you are confused about where to put the get()/first() for getting the collection or a single row here is the way:
$query = Model::where('field1', 1)
->whereNull('field2')
->where(function ($query) {
$query->where('datefield', '<', $date)
->orWhereNull('datefield');
}
)->get();

Related

Yii2 query with all() returns less data than expected

I want to find all data from database with this query:
$dataSearch = House::find()
->select(["number","DATE(reg_date) AS date","((value) > 100) AS result","info"])
->join("INNER JOIN", Owner::tableName(), Owner::tableName().'.number_ow= '.House::tableName().'.number_ow')
->andWhere([House::tableName().'.number_ow'=>$house->number_ow])
->andFilterWhere([House::tableName().'.space'=>$space])
->orderBy([House::tableName().'.reg_date'=>SORT_DESC,'info'=>SORT_ASC]);
$data = $dataSearch->asArray()->all();
If I perform the query with all() return only a few part of the results, but if I perform the raw SQL query on the database, I get all the results. I don't understand where the problem is.
This is raw SQL:
SELECT `number`, DATE(reg_date) AS date, ((value) > 100) AS result, `info`
FROM `ho_house` INNER JOIN `ho_owner` ON ho_owner.number_ow = oh_ho_house.number_ow
WHERE (`ho_house`.`number_ow`=2100174106) AND (`ho_house`.`space`='m')
ORDER BY `ho_house`.`reg_date` DESC, `info`
That is because ActiveQuery tries to remove duplicated models from results of query with JOIN (for example if house have 2 owners, house data will be repeated twice in results set). In your case, if you want to raw data from database, you should use Query:
$dataSearch = (new Query())
->select(["number","DATE(reg_date) AS date","((value) > 100) AS result","info"])
->from(House::tableName())
->join("INNER JOIN", Owner::tableName(), Owner::tableName().'.number_ow= '.House::tableName().'.number_ow')
->andWhere([House::tableName().'.number_ow'=>$house->number_ow])
->andFilterWhere([House::tableName().'.space'=>$space])
->orderBy([House::tableName().'.reg_date'=>SORT_DESC,'info'=>SORT_ASC]);
$data = $dataSearch->all();
But if you really need ActiveQuery, you should configure $indexBy to return unique ID for every row.
Replace andWhere with Where Check this code
$dataSearch = House::find()
->select(["number","DATE(reg_date) AS date","((value) > 100) AS result","info"])
->join("INNER JOIN", Owner::tableName(), Owner::tableName().'.number_ow= '.House::tableName().'.number_ow')
->where([House::tableName().'.number_ow'=>$house->number_ow])
->andFilterWhere([House::tableName().'.space'=>$space])
->orderBy([ClosedOperation::tableName().'.reg_date'=>SORT_DESC,'info'=>SORT_ASC]);
$data = $dataSearch->asArray()->all();

Filtering by sum of rows - Propel

I have a virtual column in my query like this:
->withColumn('SUM(retoure_menge)', 'return_quantity')
and I want to filter my query to only have this sum greater than zero.
How can I do something similar to
->filterByReturnQuantity(array('min' => 0))
?
Something like this should do the trick.
$query->withColumn('SUM(retoure_menge)', 'return_quantity')
->where('return_quantity > 0')
->find();

what the meaning mergeBindings in laravel

hy I'm new in laravel 4 and I have found code like this
$sub = Abc::where(..)->groupBy(..); // Eloquent Builder instance
$count = DB::table( DB::raw("({$sub->toSql()}) as sub") )
->mergeBindings($sub->getQuery())
->count();
my quetion is
1. what the meaning mergeBindings($sub->getQuery()) and give me example for using mergeBindings
assume your first query is like this:
$sub = Abc::where('type', 1)->groupBy(..);
then when we convert it to sql:
$sub->toSql();
this will return query string some thing like this:
SELECT * FROM abc where abc.type = ? GROUp BY ...
you can see the "?" as the type value which will be binded (replaced by 1) when the PDO executes that query string
So when we use that sub query in another query as you do in
$count = DB::table( DB::raw("({$sub->toSql()}) as sub") )
->mergeBindings($sub->getQuery())
->count();
you have converted the first sub query to sql string, BUT the second query does not know any thing about your first sub query binding which in this example the value 1
so we need to merge the binding from the first sub query into the last query
so that the last query when executes it will know the value 1 and binds it to the
where clause in replace of "?", and your final executed query will be something like this
(SELECT count(*) from abc where type = 1 GROUP BY ...) as sub
and thats it the use of mergeBindings() method
i hope this makes things clear for your question.
thanks,

How do I do a type cast in Laravel Fluent?

How can I do a type cast for comparing values in Laravel Fluent? For example if I have the following MySQL:
SELECT * from table1 WHERE CAST(`values` AS SIGNED) > $myVar
This is what I currently have after writing the above in Fluent:
$query = DB::connection('mysql')->table('table1')
->where('values', '>', $myVar);
Currently the database is treating this as a string. The column in the table needs to be kept as a varchar for other reasons. How can I do the type cast for this particular query in Laravel Fluent?
Untested, but I believe this should work:
$query = DB::connection('mysql')->table('table1')
->where(DB::raw('CAST(values AS SIGNED)'), '>', $myVar);
Also
$query= DB::connection('mysql')
->table('table1')
->whereRaw('CAST(values AS SIGNED) > '.$myVar);
works

Select all fields where fieldone is not equal to null + Propel

I have a question about using the propel ORM and creating a query.
I have a table "locations" with fields:
location
sublocation
postcode
street
number
Now I want to select all the locations where the location field IS NOT equal to 'null'.
How can I do this? I've tried this but I get back all the results ...
Tried query: $locations = LocationQuery::create()->where('location' != null)->find();
You can use this:
->filterByColumnName(null, Criteria::NOT_EQUAL)
There are various 'Criteria' uses in propel, listed here: propel criteria
There isn't an exact sample for this on the site, the closest is this:
->filterByTags(array('novel', 'russian'), Criteria::CONTAINS_NONE)
You can also use
->filterByColumnName(null, CRITERIA::ISNOTNULL)
I don't know propel. But the proper SQL syntax for the expression would be:
$locations = LocationQuery::create()->where('location is not null')->find();
Any comparison to NULL in SQL returns NULL, which is treated as false. With the exception of is null and is not null.
You can reference all of the Propel 2 comparison types for CRITERIA::_needed_type_ here.
EQUAL
NOT_EQUAL
ALT_NOT_EQUAL
GREATER_THAN
LESS_THAN
GREATER_EQUAL
LESS_EQUAL
LIKE
NOT_LIKE
CONTAINS_ALL
CONTAINS_SOME
CONTAINS_NONE
ILIKE
NOT_ILIKE
CUSTOM
RAW
CUSTOM_EQUAL
DISTINCT
IN
NOT_IN
ALL
JOIN
BINARY_AND
BINARY_OR
ASC
DESC
ISNULL
ISNOTNULL
CURRENT_DATE
CURRENT_TIME
CURRENT_TIMESTAMP
LEFT_JOIN
RIGHT_JOIN
INNER_JOIN
LOGICAL_OR
LOGICAL_AND

Categories