How to use pagination on DB::select(query) - Laravel - mysql

i have some query and i just know how to query on mysql (phpmyadmin)
i got information if using DB::select we cannot to use paginate, so we need change to DB::table(some query) to using pagination.
but the problem is i am confuse how to convert my query into DB::table(some query)
Here is my code
$daily = DB::select("
SELECT
employees.employee_name,
COUNT(DISTINCT DATE(attendance.attendance_datetime)) as jumlah,
locations.location_name,
TIME(MIN(attendance.attendance_datetime)) as check_in,
CASE
WHEN ISNULL(TIME(MIN(attendance.attendance_datetime))) THEN attendance_absence.remarks
WHEN TIME(MIN(attendance.attendance_datetime)) > '08:05:00' THEN (SELECT TIMEDIFF('08:05:00', MIN(TIME(attendance_datetime))))
WHEN TIME(MIN(attendance.attendance_datetime)) <= '08:05:00' THEN 'Good'
ELSE 'No Record'
END as detail_telat,
attendance_absence.remarks as remarks
FROM
employees
LEFT JOIN attendance ON employees.employee_name = attendance.attendance_name AND DATE(attendance.attendance_datetime) = '$date'
LEFT JOIN locations ON employees.location_id = locations.id
LEFT JOIN attendance_absence ON attendance_absence.employee_name = employees.employee_name AND attendance_absence.absences_date = '$date'
WHERE locations.location_name LIKE '%'
GROUP BY employees.employee_name
ORDER BY employees.employee_name
")->paginate(3);
please help me to convert my query into eloquent or query builder, or any suggestion ?

Currently, pagination operations that use a groupBy statement cannot be executed efficiently by Laravel. If you need to use a groupBy with a paginated result set, it is recommended that you query the database and create a paginator manually.
Check documentation

Related

Rewrite the raw DB query to query builder in laravel 8

I'm trying to convert a raw query to a Laravel query builder but when I use the raw method I can't make it to write in a query builder
Here is my raw query
SELECT GROUP_CONCAT(CONCAT(a.qty,' ',a.uqc) SEPARATOR ' ,') as quantity,a.exporter
FROM (select sum(shipping_bill_items.quantity) as qty, `exporters`.name as exporter,`shipping_bill_items`.uqc
from `shipping_bill_items`
inner join `shipping_bill` on `shipping_bill`.`id` = `shipping_bill_items`.`shipping_bill_id`
inner join `exporters` on `exporters`.`id` = `shipping_bill`.`exporter_id`
group by `exporters`.name,`shipping_bill_items`.`uqc`
ORDER BY `exporters`.`name` ASC ) a
group by a.exporter;
I tried to write seems couldn't help any please help me to rewrite this!
below which I tired to rewrite attempt to solve the problem
$Details=DB::select('a.exporter')
->addSelect(DB::raw("GROUP_CONCAT(CONCAT(a.qty,' ', a.uqc) SEPARATOR ' ,') as quantity"))
->from("select sum(shipping_bill_items.quantity) as qty, 'exporters'.name as exporter, 'shipping_bill_items'.uqc from 'shipping_bill_items' inner join 'shipping_bill' on 'shipping_bill'.'id' = 'shipping_bill_items'.'shipping_bill_id' inner join 'exporters' on 'exporters'.'id' = 'shipping_bill'.'exporter_id' group by 'exporters'.name, 'shipping_bill_items'.'uqc' ORDER BY 'exporters'.'name' ASC as a")
->groupBy('a.exporter')
->get();
I tried to add an image for references but I couldn't add it here is the table that I want to achieve a result
quantity
exporter
45.65 MTS
1st Exporter
1404.25 LTR,114170 NO
2nd Exporter
5168 NOS,47856 PCS,74648 SET
3ed Exporter

Don't know how to create this MySQL statement in sqlalchemy

I have the following MySQL statement which does what I want:
SELECT scores.score, registrations.parade, AVG(scores.score) as result
FROM scores
JOIN registrations ON scores.registrationId=registrations.id
where registrations.parade=1
GROUP BY scores.registrationId
ORDER BY result DESC
basically, with sqlalchemy I think I would start with:
db.session.query(Scores, func.avg(Scores.score).label('result'))
This is because I do not need the information from registrations (it's linked to each other in the model). I only join the registrations in the MySQL statement because I need to filter on its parade.id
Below is what I have been trying so far but does not work:
scores = db.session.query(Scores,func.avg(Scores.score).label('result'))\
.filter(Registrations.parade == 1)\
.group_by(Scores.registrationId)\
.order_by(desc('result'))
You are missing the join
scores = db.session.query(Scores.score,func.avg(Scores.score).label('result'))\
.join(Registrations)\
.filter(Registrations.parade == 1)\
.group_by(Scores.registrationId)\
.order_by(desc('result'))
Another issue is, that you should have an aggretation function for registrations.parade or else include it in the group_by statement.

How to use MAX function in yii2 query?

I have a query:
SELECT hs.*
FROM hire_screening hs
INNER JOIN
(SELECT resume_id, MAX(created_date) AS MaxDateTime
FROM hire_screening
GROUP BY resume_id) hire_screening
ON hs.resume_id = hire_screening.resume_id
AND hs.created_date = hire_screening.MaxDateTime
This is my table:
I need the answer like this:
I tried this:
$query = HireScreening::find()-
->select(["hire_screening.screening_id","hs.resume_id",
"MAX(hs.created_date) AS
MaxDateTime","hs.screening_by","hsl.screening_level as
hr_level","hss.screening_status as
hr_status","hr.candidate_name","hsm.screening_mode as
hr_mode","hire_screening.created_date","hs.screening_date"])
->innerJoin('hire_screening as hs','hs.resume_id =
hire_screening.resume_id')
->leftJoin('hire_screening_level as
hsl','hire_screening.screening_level = hsl.id')
->leftJoin('hire_screening_mode as
hsm','hire_screening.screening_mode = hsm.id')
->leftJoin('hire_screening_status as
hss','hire_screening.screening_status = hss.id')
->leftJoin('hire_resume as
hr','hire_screening.resume_id=hr.resume_id')
//->where(['hire_screening.created_date = MaxDateTime'])
->groupBy(['resume_id']);
//->having(['hire_screening.created_date' =>
'hs.MaxDateTime']);
$query->orderBy(['created_date' => SORT_DESC]);
But it didn't shows the answer. I need the distinct resume_id's with latest created date. The sql query shows the correct answer.I want to write this query in my search model. Please help me to convert this query into yii2.
If there is a table MyTable, then you can use simplier query grouping the table by resume_id:
SELECT
screening_id,
resume_id,
screening_by,
screening_date,
screening_level,
screening_mode,
screening_status,
reject_reason,
remarks,
created_by,
MAX(created_date) AS created_date
FROM MyTable
GROUP BY resume_id;
Using simplify query helps to avoid an errors. Also you could create a view or a stored procedure using the query and call this from your PHP code.

INNER JOIN Results from Select Statement using Doctrine QueryBuilder

Can you use Doctrine QueryBuilder to INNER JOIN a temporary table from a full SELECT statement that includes a GROUP BY?
The ultimate goal is to select the best version of a record. I have a viewVersion table that has multiple versions with the same viewId value but different timeMod. I want to find the version with the latest timeMod (and do a lot of other complex joins and filters on the query).
Initially people assume you can do a GROUP BY viewId and then ORDER BY timeMod, but ORDER BY has no effect on GROUP BY, and MySQL will return random results. There are a ton of answers out there (e.g. here) that explain the problem with using GROUP and offer a solution, but I am having trouble interpreting the Doctrine docs to find a way to implement the SQL with Doctrine QueryBuilder (if it's even possible). Why don't I just use DQL? I may have to, but I have a lot of dynamic filters and joins that are much easier to do with QueryBuilder, so I wanted to see if that's possible.
Sample MySQL to Reproduce in Doctrine QueryBuilder
SELECT vv.*
FROM view_version vv
#inner join only returns where the result sets overlap, i.e. one record
INNER JOIN (
SELECT MAX(timeMod) maxTimeMod, viewId
FROM view_version
GROUP BY viewId
) version ON version.viewId = vv.viewId AND vv.timeMod = version.maxTimeMod
#join other tables for filter, etc
INNER JOIN view v ON v.id = vv.viewId
INNER JOIN content_type c ON c.id = v.contentTypeId
WHERE vv.siteId=1
AND v.contentTypeId IN (2)
ORDER BY vv.title ASC;
Theoretical Solution via Query Builder (not working)
I am thinking that the JOIN needs to inject a DQL statement, e.g.
$em = $this->getDoctrine()->getManager();
$viewVersionRepo = $em->getRepository('GutensiteCmsBundle:View\ViewVersion');
$queryMax = $viewVersionRepo->createQueryBuilder()
->addSelect('MAX(timeMod) AS timeModMax')
->addSelect('viewId')
->groupBy('viewId');
$queryBuilder = $viewVersionRepo->createQueryBuilder('vv')
// I tried putting the query in a parenthesis, to no avail
->join('('.$queryMax->getDQL().')', 'version', 'WITH', 'vv.viewId = version.viewId AND vv.timeMod = version.timeModMax')
// Join other Entities
->join('e.view', 'view')
->addSelect('view')
->join('view.contentType', 'contentType')
->addSelect('contentType')
// Perform random filters
->andWhere('vv.siteId = :siteId')->setParameter('siteId', 1)
->andWhere('view.contentTypeId IN(:contentTypeId)')->setParameter('contentTypeId', $contentTypeIds)
->addOrderBy('e.title', 'ASC');
$query = $queryBuilder->getQuery();
$results = $query->getResult();
My code (which may not match the above example perfectly) outputs:
SELECT e, view, contentType
FROM Gutensite\CmsBundle\Entity\View\ViewVersion e
INNER JOIN (
SELECT MAX(v.timeMod) AS timeModMax, v.viewId
FROM Gutensite\CmsBundle\Entity\View\ViewVersion v
GROUP BY v.viewId
) version WITH vv.viewId = version.viewId AND vv.timeMod = version.timeModMax
INNER JOIN e.view view
INNER JOIN view.contentType contentType
WHERE e.siteId = :siteId
AND view.contentTypeId IN (:contentTypeId)
ORDER BY e.title ASC
This Answer seems to indicate that it's possible in other contexts like IN statements, but when I try the above method in the JOIN, I get the error:
[Semantical Error] line 0, col 90 near '(SELECT MAX(v.timeMod)': Error: Class '(' is not defined.
A big thanks to #AdrienCarniero for his alternative query structure for sorting the highest version with a simple JOIN where the entity's timeMod is less than the joined table timeMod.
Alternative Query
SELECT view_version.*
FROM view_version
#inner join to get the best version
LEFT JOIN view_version AS best_version ON best_version.viewId = view_version.viewId AND best_version.timeMod > view_version.timeMod
#join other tables for filter, etc
INNER JOIN view ON view.id = view_version.viewId
INNER JOIN content_type ON content_type.id = view.contentTypeId
WHERE view_version.siteId=1
# LIMIT Best Version
AND best_version.timeMod IS NULL
AND view.contentTypeId IN (2)
ORDER BY view_version.title ASC;
Using Doctrine QueryBuilder
$em = $this->getDoctrine()->getManager();
$viewVersionRepo = $em->getRepository('GutensiteCmsBundle:View\ViewVersion');
$queryBuilder = $viewVersionRepo->createQueryBuilder('vv')
// Join Best Version
->leftJoin('GutensiteCmsBundle:View\ViewVersion', 'bestVersion', 'WITH', 'bestVersion.viewId = e.viewId AND bestVersion.timeMod > e.timeMod')
// Join other Entities
->join('e.view', 'view')
->addSelect('view')
->join('view.contentType', 'contentType')
->addSelect('contentType')
// Perform random filters
->andWhere('vv.siteId = :siteId')->setParameter('siteId', 1)
// LIMIT Joined Best Version
->andWhere('bestVersion.timeMod IS NULL')
->andWhere('view.contentTypeId IN(:contentTypeId)')->setParameter('contentTypeId', $contentTypeIds)
->addOrderBy('e.title', 'ASC');
$query = $queryBuilder->getQuery();
$results = $query->getResult();
In terms of performance, it really depends on the dataset. See this discussion for details.
TIP: The table should include indexes on both these values (viewId and timeMod) to speed up results. I don't know if it would also benefit from a single index on both fields.
A native SQL query using the original JOIN method may be better in some cases, but compiling the query over an extended range of code that dynamically creates it, and getting the mappings correct is a pain. So this is at least an alternative solution that I hope helps others.

MySQL COUNT() causing empty array() return

MySQL Server Version: Server version: 4.1.14
MySQL client version: 3.23.49
Tables under discussion: ads_list and ads_cate.
Table Relationship: ads_cate has many ads_list.
Keyed by: ads_cate.id = ads_list.Category.
I am not sure what is going on here, but I am trying to use COUNT() in a simple agreggate query, and I get blank output.
Here is a simple example, this returns expected results:
$queryCats = "SELECT id, cateName FROM ads_cate ORDER BY cateName";
But if I modify it to add the COUNT() and the other query data I get no array return w/ print_r() (no results)?
$queryCats = "SELECT ads_cate.cateName, ads_list.COUNT(ads_cate.id),
FROM ads_cate INNER JOIN ads_list
ON ads_cate.id = ads_list.category
GROUP BY cateName ORDER BY cateName";
Ultimately, I am trying to get a count of ad_list items in each category.
Is there a MySQL version conflict on what I am trying to do here?
NOTE: I spent some time breaking this down, item by item and the COUNT() seems to cause the array() to disappear. And the the JOIN seemed to do the same thing... It does not help I am developing this on a Yahoo server with no access to the php or mysql error settings.
I think your COUNT syntax is wrong. It should be:
COUNT(ads_cate.id)
or
COUNT(ads_list.id)
depending on what you are counting.
Count is an aggregate. means ever return result set at least one
here you be try count ads_list.id not null but that wrong. how say Myke Count(ads_cate.id) or Count(ads_list.id) is better approach
you have inner join ads_cate.id = ads_list.category so Count(ads_cate.id) or COUNT(ads_list.id) is not necessary just count(*)
now if you dont want null add having
only match
SELECT ads_cate.cateName, COUNT(*),
FROM ads_cate INNER JOIN ads_list
ON ads_cate.id = ads_list.category
GROUP BY cateName
having not count(*) is null
ORDER BY cateName
all
SELECT ads_cate.cateName, IFNULL(COUNT(*),0),
FROM ads_cate LEFT JOIN ads_list
ON ads_cate.id = ads_list.category
GROUP BY cateName
ORDER BY cateName
Did you try:
$queryCats = "SELECT ads_cate.cateName, COUNT(ads_cate.id)
FROM ads_cate
JOIN ads_list ON ads_cate.id = ads_list.category
GROUP BY ads_cate.cateName";
I am guessing that you need the category to be in the list, in that case the query here should work. Try it without the ORDER BY first.
You were probably getting errors. Check your server logs.
Also, see what happens when you try this:
SELECT COUNT(*), category
FROM ads_list
GROUP BY category
Your array is empty or disappear because your query has errors:
there should be no comma before the FROM
the "ads_list." prefix before COUNT is incorrect
Please try running that query directly in MySQL and you'll see the errors. Or try echoing the output using mysql_error().
Now, some other points related to your query:
there is no need to do ORDER BY because GROUP BY by default sorts on the grouped column
you are doing a count on the wrong column that will always give you 1
Perhaps you are trying to retrieve the count of ads_list per ads_cate? This might be your query then:
SELECT `ads_cate`.`cateName`, COUNT(`ads_list`.`category`) `cnt_ads_list`
FROM `ads_cate`
INNER JOIN `ads_list` ON `ads_cate`.`id` = `ads_list`.`category`
GROUP BY `cateName`;
Hope it helps?