Laravel DB query group by output is different - mysql

I have the following implemented query in my Laravel project, the query is working if I copy paste in the console, but the DB object sets on subquery group by zeit_von to group by zeit_von is null
$data = DB::table('e_supply AS s')
->select(
DB::raw('count(s.employee) as anzahl_employee'),
DB::raw('group_concat(a.account_lastname order by a.account_lastname ) AS employee_names'),
DB::raw('date_format(s.zeit_von, "%Y") as y'),
DB::raw('date_format(s.zeit_von, "%m") as m'),
DB::raw('date_format(s.zeit_von, "%d") as d'),
DB::raw('date_format(s.zeit_von, "%h") as h')
)
->leftJoin('phpgw_accounts AS a', 'a.account_id', '=', 's.employee')
->where('deleted', 0)
->whereIn('supply_status', [1,3])
->where(
DB::raw('( select count(cal_id) from phpgw_cal_utf8 as c
where c.owner=s.employee
and deleted=0
and date_format(s.zeit_von, "%d.%m.%y")=date_format(from_unixtime(c.mdatetime), "%d.%m.%y")
and c.category="Krank"
)<1 and date_format((s.zeit_von), "%Y")="'.$year.'" group by zeit_von'
)
)
->get();
What i'm missing in this case?

using whereRaw for a subquery suppress the problem what I faced
$data = DB::table('e_supply AS s')
->select(
'zeit_von as raw_time',
DB::raw('count(distinct s.employee) as anzahl_employee'),
DB::raw('group_concat(a.account_lastname order by a.account_lastname ) AS employee_names'),
DB::raw('date_format(s.zeit_von, "%Y") as y'), DB::raw('date_format(s.zeit_von, "%m") as m'),
DB::raw('date_format(s.zeit_von, "%d") as d'), DB::raw('date_format(s.zeit_von, "%h") as h')
)
->leftJoin('phpgw_accounts AS a', 'a.account_id', '=', 's.employee')
->where('deleted', 0)
->whereIn('supply_status', [1, 3])
->whereRaw(
DB::raw('( select count(cal_id) from phpgw_cal_utf8 as c
where c.owner=s.employee
and deleted=0
and date_format(s.zeit_von, "%d.%m.%y")=date_format(from_unixtime(c.mdatetime), "%d.%m.%y")
and c.category="Krank"
)<1'
)
)
->whereYear('s.zeit_von', $year)
->groupBy('zeit_von')
->get();

Related

How to make Laravel eloquent request with 1 filter on many fields

In my Laravel 5.7/ mysql app I make request on a form with 10 filter inputs,
one of them ($filter_search) if non empty must be compared with all fields(string, number,
date, ref to fields of other tables) in resulting listing.
I made scope on this table fields:
public function scopeGetBySearch($query, $search = null)
{
if (empty($search)) {
return $query;
}
$tb= with(new StorageSpace)->getTable();
return $query->where(
$tb.'.number', $search
) ->orWhere(function ($query) use ($search, $tb) {
$query->where( $tb.".notes", 'like', '%'.$search.'%' )
->orWhere($tb.".selling_range", $search)
->orWhere($tb.".actual_storage_rent", $search)
->orWhere($tb.".insurance_vat", $search)
// ->havingRaw("job_ref_no", $search)
})
But I have a problem how can I set filter on job_ref_no field from other table :
$storageSpacesCollection = StorageSpace
::getByStatus($filter_status)
->getById($relatedStorageSpacesArray)
->getByLocationId($filter_location_id, 'warehouses')
->getByCapacityCategoryId($filter_capacity_category_id, 'storage_capacities')
->getByLevel($filter_level)
->getByNumber($filter_number, true)
->orderBy('storage_spaces.id', 'asc')
->getByStorageCapacityId($filter_storage_capacity_id)
->getByClientId($filter_client_id)
->getByColorId($filter_color_id)
->getBySearch($filter_search)
// ->havingRaw("job_ref_no = " . $filter_search)
->leftJoin( 'storage_capacities', 'storage_capacities.id', '=', 'storage_spaces.storage_capacity_id' )
->leftJoin( 'warehouses', 'warehouses.id', '=', 'storage_spaces.warehouse_id' )
->leftJoin( 'clients', 'clients.id', '=', 'storage_spaces.client_id')
->select(
"storage_spaces.*",
\DB::raw( "CONCAT(storage_capacities.count, ' ', storage_capacities.sqft ) as storage_capacity_name" ),
\DB::raw("( SELECT check_ins.job_ref_no FROM check_ins WHERE // I got job_ref_no field in subquesry check_ins.storage_space_id=storage_spaces.id ORDER BY check_ins.id ASC limit 1 ) AS job_ref_no"),
"warehouses.name as warehouse_name",
"clients.full_name as client_full_name")
->get();
havingRaw does not work both in the scope and in the request above if to uncomment it.
I tried to use addSelect, like:
But with request :
$storageSpacesCollection = StorageSpace
::getByStatus($filter_status)
->whereRaw('storage_spaces.id <= 8') // DEBUGGING
->getById($relatedStorageSpacesArray)
->getByLocationId($filter_location_id, 'warehouses')
->getByCapacityCategoryId($filter_capacity_category_id, 'storage_capacities')
->getByLevel($filter_level)
->getByNumber($filter_number, true)
->orderBy('storage_spaces.id', 'asc')
->getByStorageCapacityId($filter_storage_capacity_id)
->getByClientId($filter_client_id)
->getByColorId($filter_color_id)
->getBySearch($filter_search)
// ->havingRaw("job_ref_no = " . $filter_search)
->leftJoin( 'storage_capacities', 'storage_capacities.id', '=', 'storage_spaces.storage_capacity_id' )
->leftJoin( 'warehouses', 'warehouses.id', '=', 'storage_spaces.warehouse_id' )
->leftJoin( 'clients', 'clients.id', '=', 'storage_spaces.client_id')
->select(
"storage_spaces.*",
\DB::raw( "CONCAT(storage_capacities.count, ' ', storage_capacities.sqft ) as storage_capacity_name" ),
"warehouses.name as warehouse_name",
"clients.full_name as client_full_name")
->addSelect([
'job_ref_no' => CheckIn::selectRaw('job_ref_no')->whereColumn('check_ins.storage_space_id', 'storage_spaces.id'),
])
->get();
But I got an error:
local.ERROR: stripos() expects parameter 1 to be string, object given {"userId":11,"email":"nilovsergey#yahoo.com","exception":"[object] (ErrorException(code: 0): stripos() expects parameter 1 to be string, object given at /mnt/_work_sdb8/wwwroot/lar/the-box-booking/vendor/laravel/framework/src/Illuminate/Database/Query/Grammars/Grammar.php:1031)
[stacktrace]
#0 [internal function]: Illuminate\\Foundation\\Bootstrap\\HandleExceptions->handleError(2, 'stripos() expec...', '/mnt/_work_sdb8...', 1031, Array)
#1 /mnt/_work_sdb8/wwwroot/lar/the-box-booking/vendor/laravel/framework/src/Illuminate/Database/Query/Grammars/Grammar.php(1031): stripos(Object(Illuminate\\Database\\Eloquent\\Builder), ' as ')
#2 [internal function]: Illuminate\\Database\\Query\\Grammars\\Grammar->wrap(Object(Illuminate\\Database\\Eloquent\\Builder))
Which way is valid ?
MODIFIED BLOCK:
I try to create sql I need manually.
With Laravel request :
$storageSpacesCollection = StorageSpace
::getByStatus($filter_status)
->whereRaw('storage_spaces.id <= 8') // DEBUGGING
->getById($relatedStorageSpacesArray)
->getByLocationId($filter_location_id, 'warehouses')
->getByCapacityCategoryId($filter_capacity_category_id, 'storage_capacities')
->getByLevel($filter_level)
->getByNumber($filter_number, true)
->orderBy('storage_spaces.id', 'asc')
->getByStorageCapacityId($filter_storage_capacity_id)
->getByClientId($filter_client_id)
->getByColorId($filter_color_id)
->getBySearch($filter_search)
->leftJoin( 'storage_capacities', 'storage_capacities.id', '=', 'storage_spaces.storage_capacity_id' )
->leftJoin( 'warehouses', 'warehouses.id', '=', 'storage_spaces.warehouse_id' )
->leftJoin( 'clients', 'clients.id', '=', 'storage_spaces.client_id')
->select(
"storage_spaces.*",
\DB::raw( "CONCAT(storage_capacities.count, ' ', storage_capacities.sqft ) as storage_capacity_name" ),
\DB::raw("( SELECT check_ins.job_ref_no FROM check_ins WHERE check_ins.storage_space_id=storage_spaces.id ORDER BY check_ins.id ASC limit 1 ) AS job_ref_no"),
"warehouses.name as warehouse_name",
"clients.full_name as client_full_name")
->get();
And tracing I see sql statement with job_ref_no column :
SELECT `storage_spaces`.*, CONCAT(storage_capacities.count, ' ', storage_capacities.sqft ) AS storage_capacity_name, ( SELECT check_ins.job_ref_no
FROM check_ins
WHERE check_ins.storage_space_id=storage_spaces.id
ORDER BY check_ins.id ASC limit 1 ) AS job_ref_no, `warehouses`.`name` AS `warehouse_name`, `clients`.`full_name` AS `client_full_name`
FROM `storage_spaces`
LEFT JOIN `storage_capacities` on `storage_capacities`.`id` = `storage_spaces`.`storage_capacity_id`
LEFT JOIN `warehouses` on `warehouses`.`id` = `storage_spaces`.`warehouse_id`
LEFT JOIN `clients` on `clients`.`id` = `storage_spaces`.`client_id`
WHERE storage_spaces.id <= 8 AND (`storage_spaces`.`number` = '999' OR
(`storage_spaces`.`notes` like '%999%' OR
`storage_spaces`.`selling_range` = '999' OR
`storage_spaces`.`actual_storage_rent` = '999' OR
`storage_spaces`.`insurance_vat` = '999') )
ORDER BY `storage_spaces`.`id` asc
I want to set filter on job_ref_no column manually :
SELECT `storage_spaces`.*, CONCAT(storage_capacities.count, ' ', storage_capacities.sqft ) AS storage_capacity_name, ( SELECT check_ins.job_ref_no
FROM check_ins
WHERE check_ins.storage_space_id=storage_spaces.id
ORDER BY check_ins.id ASC limit 1 ) AS job_ref_no, `warehouses`.`name` AS `warehouse_name`, `clients`.`full_name` AS `client_full_name`
FROM `storage_spaces`
LEFT JOIN `storage_capacities` on `storage_capacities`.`id` = `storage_spaces`.`storage_capacity_id`
LEFT JOIN `warehouses` on `warehouses`.`id` = `storage_spaces`.`warehouse_id`
LEFT JOIN `clients` on `clients`.`id` = `storage_spaces`.`client_id`
WHERE storage_spaces.id <= 8 AND (`storage_spaces`.`number` = '999' OR
(`storage_spaces`.`notes` like '%999%' OR
`storage_spaces`.`selling_range` = '999' OR
`storage_spaces`.`actual_storage_rent` = '999' OR
`storage_spaces`.`insurance_vat` = '999' OR
job_ref_no = '999' ) // I added this line #
)
ORDER BY `storage_spaces`.`id` asc
But I got error :
Error in query (1054): Unknown column 'job_ref_no' in 'where clause'
Which is valid way in raw sql and how it can be implemented with eloquent ?
MODIFIED BLOCK # 2:
I try to make with join:
$storageSpacesCollection = StorageSpace
::getByStatus($filter_status)
->getById($relatedStorageSpacesArray)
->getByLocationId($filter_location_id, 'warehouses')
->getByCapacityCategoryId($filter_capacity_category_id, 'storage_capacities')
->getByLevel($filter_level)
->getByNumber($filter_number, true)
->orderBy('storage_spaces.id', 'asc')
->getByStorageCapacityId($filter_storage_capacity_id)
->getByClientId($filter_client_id)
->getByColorId($filter_color_id)
->getBySearch($filter_search)
->leftJoin( 'storage_capacities', 'storage_capacities.id', '=', 'storage_spaces.storage_capacity_id' )
->leftJoin( 'warehouses', 'warehouses.id', '=', 'storage_spaces.warehouse_id' )
->leftJoin( 'clients', 'clients.id', '=', 'storage_spaces.client_id')
->leftJoin( 'check_ins', 'check_ins.storage_space_id', '=', 'storage_spaces.id') // I ADDED THIS LINE
->select(
"storage_spaces.*",
\DB::raw( "CONCAT(storage_capacities.count, ' ', storage_capacities.sqft ) as storage_capacity_name" ),
// \DB::raw("( SELECT check_ins.job_ref_no FROM check_ins WHERE check_ins.storage_space_id=storage_spaces.id ORDER BY check_ins.id ASC limit 1 ) AS job_ref_no"),
"warehouses.name as warehouse_name",
"check_ins.job_ref_no as job_ref_no",
"clients.full_name as client_full_name")
->distinct()
->get();
and I have a sql :
SELECT distinct `storage_spaces`.*, CONCAT(storage_capacities.count, ' ', storage_capacities.sqft ) AS storage_capacity_name,
`warehouses`.`name` AS `warehouse_name`, `check_ins`.`job_ref_no` AS `job_ref_no`, `clients`.`full_name` AS `client_full_name`
FROM `storage_spaces`
LEFT JOIN `storage_capacities` on `storage_capacities`.`id` = `storage_spaces`.`storage_capacity_id`
LEFT JOIN `warehouses` on `warehouses`.`id` = `storage_spaces`.`warehouse_id`
LEFT JOIN `clients` on `clients`.`id` = `storage_spaces`.`client_id`
LEFT JOIN `check_ins` on `check_ins`.`storage_space_id` = `storage_spaces`.`id`
WHERE ( `storage_spaces`.`number` = 'S1-102' OR (`storage_spaces`.`notes` like '%S1-102%' OR `storage_spaces`.`selling_range` = 'S1-102' OR
`storage_spaces`.`actual_storage_rent` = 'S1-102' OR `storage_spaces`.`insurance_vat` = 'S1-102' OR `job_ref_no` = 'S1-102') )
ORDER BY `storage_spaces`.`id` asc
I have have different results
I need to get only last row from check_ins, that is why in my request I have limit 1:
\DB::raw("( SELECT check_ins.job_ref_no FROM check_ins WHERE check_ins.storage_space_id=storage_spaces.id ORDER BY check_ins.id ASC limit 1 ) AS job_ref_no"),
that is why have have several rows of as storage_spaces as all check_ins ae joined
2) I have all rows from storage_spaces and I do not see why
I tried to change leftJoin with Join /rightJoin but it did not help...
Thanks!
You need to set the join into the main query instead of select query because in select query it's not a actual column which you set into the where condition.
I found a decision addin in scope :
->orWhereRaw("(SELECT check_ins.job_ref_no FROM check_ins WHERE
check_ins.storage_space_id=storage_spaces.id ORDER BY check_ins.id ASC LIMIT 1) = '".$search."'")
and that works for me.

mysql query "Invalid use of group function"

I have query like this
SELECT id_order_history,
( MAX(DATE(date_add)) - MIN(DATE(date_add))) AS selisih
FROM ps_order_history
WHERE id_order_state IN ('2', '48', '49', '50')
AND MONTH (date_add) = '05'
AND YEAR (date_add) = '2016'
AND (MAX(DATE(date_add)) - MIN(DATE(date_add)) > 5)
GROUP BY id_order
and it has an issue in
AND (MAX(DATE(date_add)) - MIN(DATE(date_add)) > 5)
How to solve it ?

MySQL cohort query result structure

I have following MySQL query:
SELECT results.YEAR , results.cohort_date , results.actives AS
active_users , user_totals.total AS cohort_size
FROM (SELECT YEAR( user.date_added) AS cohort_date ,
COUNT(DISTINCT user_log.user_id) AS actives,
ROUND( DATEDIFF( user_log.login_date ,user.date_added)) AS YEAR
FROM user
JOIN user_log ON user_log.user_id = user.id
GROUP BY cohort_date, YEAR) AS results
JOIN (SELECT YEAR( user.date_added) AS cohort_date, COUNT( user.id) AS total
FROM user
GROUP BY cohort_date) AS user_totals
ON user_totals.cohort_date = results.cohort_date
Which gives result in following structure:
YEAR cohort_date cohort_size active_users
[1, 1973, 1000, 750],
[2, 1973, 1000, 300],
[3, 1973, 1000, 400],
[1, 1268, 549, 336],
[2, 1268, 549, 221],
How can I rewrite query so that it returns data in this format?
[1973, 1000, 750,300,400],
[1268, 549, 336,221],
Use group_concat() function to generate comma separated list of values by group:
SELECT results.cohort_date , user_totals.total AS cohort_size, group_concat(results.actives) AS
active_users
FROM (SELECT YEAR( user.date_added) AS cohort_date ,
COUNT(DISTINCT user_log.user_id) AS actives,
ROUND( DATEDIFF( user_log.login_date ,user.date_added)) AS YEAR
FROM user
JOIN user_log ON user_log.user_id = user.id
GROUP BY cohort_date, YEAR) AS results
JOIN (SELECT YEAR( user.date_added) AS cohort_date, COUNT( user.id) AS total
FROM user
GROUP BY cohort_date) AS user_totals
ON user_totals.cohort_date = results.cohort_date
GROUP BY results.cohort_date , user_totals.total

Laravel Multiple WHERE() Operator Precedence

I have the following query written using Eloquent:
Contact::select(DB::raw("DATE_FORMAT(DATE(`created_at`),'%b %d') as date"))
->addSelect(DB::raw("`created_at`"))
->addSelect(DB::raw("COUNT(*) as `count`"))
->where('created_at', '>', $date)
->ofType($type)
->groupBy('date')
->orderBy('created_at', 'ASC')
->lists('count', 'date');
You can see it uses a query scope method ofType() Here is that method, it just adds a bunch of extra where clauses to the query:
return $query->where('list_name', '=', 'Apples')
->orWhere('list_name', '=', 'Oranges')
->orWhere('list_name', '=', 'Pears')
->orWhere('list_name', '=', 'Plums')
->orWhere('list_name', '=', 'Blueberries');
Ultimately this results in the following real SQL query:
SELECT DATE_FORMAT(DATE(`created_at`),'%b %d') as date,`created_at`, COUNT(*) as `count`
FROM `contacts`
WHERE `created_at` > '2014-10-02 00:00:00'
AND `list_name` = 'Apples'
OR `list_name` = 'Oranges'
OR `list_name` = 'Pears'
OR `list_name` = 'Plums'
OR `list_name` = 'Blueberries'
GROUP BY `date`
ORDER BY `created_at` ASC
The problem is, the WHERE created_at > '2014-10-02 00:00:00' clause is being missed when the OR clauses kick in. Due to operator precendence. I need to wrap all the clauses after the first AND in parentheses, like so:
SELECT DATE_FORMAT(DATE(`created_at`),'%b %d') as date,`created_at`, COUNT(*) as `count`
FROM `contacts`
WHERE `created_at` > '2014-10-02 00:00:00'
AND
(`list_name` = 'Apples'
OR `list_name` = 'Oranges'
OR `list_name` = 'Pears'
OR `list_name` = 'Plums'
OR `list_name` = 'Blueberries')
GROUP BY `date`
ORDER BY `created_at` ASC
So, my question is, how would I achieve this using the eloquent query builder. Thank you.
Thanks to mOrsa I've figured it out, by changing my query scope method to take advantage of advanced where:
return $query->where(function($query){
$query->orWhere('list_name', '=', 'Apples')
->orWhere('list_name', '=', 'Oranges')
->orWhere('list_name', '=', 'Pears')
->orWhere('list_name', '=', 'Plums')
->orWhere('list_name', '=', 'Blueberries');
});
I get the desired SQL.

Unknown column in subquery - mysql

I am very close to completing this difficult query. It's quite long, so hopefully not too overwhelming. But in my case statment in the select block I am referencing a union from my where statement. It is giving me "MySQL Database Error: Unknown column 'U.EmpID' in 'where clause'". Any help would be much appreciated. And here is the query:
SELECT U.EmpID,
CASE
WHEN ((SELECT COUNT(*)
FROM (SELECT *
FROM timeclock_copy tp
WHERE PunchEvent = 'breakin'
AND DATE(tp.PunchDateTime) =
'2013-11-12'
AND tp.EmpID = U.EmpID) AS s) > 1)
AND ((SELECT COUNT(*)
FROM (SELECT *
FROM timeclock_copy tp
WHERE PunchEvent = 'breakout'
AND DATE(tp.PunchDateTime) =
'2013-11-12'
AND tp.EmpID = U.EmpID) AS s) > 1)
THEN
"MULTIPLE BREAKS"
ELSE
"ONE BREAK"
END
AS Lunch
FROM ((SELECT `enter`.EmpID,
`enter`.PunchDateTime AS `time`,
DATE_FORMAT(`enter`.PunchDateTime, '%m-%d-%Y')
AS 'Punch Date',
TIMESTAMPDIFF(SECOND,
`enter`.PunchDateTime,
'2003-05-01 00:00:00')
AS `delta`
FROM timeclock_copy AS `enter`
WHERE `enter`.`In-Out` = 1)
UNION
(SELECT `leave`.EmpID,
`leave`.PunchDateTime AS `time`,
DATE_FORMAT(`leave`.PunchDateTime, '%m-%d-%Y')
AS 'Punch Date',
-TIMESTAMPDIFF(SECOND,
`leave`.PunchDateTime,
'2003-05-01 00:00:00')
AS `delta`
FROM timeclock_copy AS `leave`
WHERE `leave`.`In-Out` = 0)) AS U
LEFT JOIN testclb.prempl pe ON u.EmpID = pe.prempl
WHERE DATE(U.`time`) >= '2013-11-12' AND DATE(U.`time`) < '2013-11-13'
GROUP BY date(U.`time`), EmpID
ORDER BY U.EmpID, U.`time` ASC
Subqueries in FROM clauses cannot be correlated with the outer statement. I think this is why you are getting the Unknown column 'U.EmpID' in 'where clause'" error.