Using same table in subquery - laravel

I am failing to convert next SQL code into laravel eloquent:
SELECT t1.template, t1.created_at
FROM sent_emails t1
where created_at = (
select max(created_at) from sent_emails t2 where t2.template = t1.template
)
group by t1.created_at, t1.template
or:
SELECT t1.template, t1.created_at
FROM sent_emails t1
JOIN
(
SELECT Max(created_at) date, template
FROM sent_emails
GROUP BY template
) AS t2
ON t1.template = t2.template
AND t1.created_at = t2.date
group by t1.created_at, t1.template
Both queries return same data set. Creating subquery in separate variable is not an option as I need multiple values to be returned from it.
I also don't know how can I set alias name if I create table using models (and not using DB::), so this is my unsuccessful try:
$sent_emails = SentEmail::where('created_at', function($query) {
SentEmail::where('template', 't1.template')->orderBy('created_at', 'desc');
})->groupBy('template', 'created_at')->get(['template', 'created_at']);

You query should be something like this (I'm not at a computer to test this, so it may require further editing)
$sent_emails = SentEmail::where('created_at', function($query) {
$query->where('created_at', SentEmail::->whereColumn('column_name', 'table.column_name')->orderBy('created_at', 'desc')->max('created_at'));
})->groupBy('template', 'created_at')->get(['template', 'created_at']);

Related

Raw Laravel query as a collection with conditions

I've got a fairly complex query that I'd rather not write in Eloquent so I've written it raw. The only problem is that I need to be able to search/filter through the data using the front-end this query is connected to.
This what I've tried but I'm getting an "Call to a member function get() on null" error.
Here's my code:
$report = collect(DB::connection('mysql2')->select("SELECT
t2.holder,
t2.merchantTransactionId,
t2.bin,
t2.last4Digits,
t3.expDate,
(CASE WHEN t3.expDate < CURDATE() THEN 'Expired'
WHEN t3.expDate > CURDATE() THEN 'Due to expire' END) AS expInfo,
t2.uuid
FROM transactions AS t2
INNER JOIN (
SELECT t1.uuid, t1.holder, t1.bin, t1.last4Digits, LAST_DAY(CONCAT(t1.expiryYear, t1.expiryMonth, '01')) AS expDate
FROM transactions t1
JOIN (SELECT t1.merchant_access
FROM total_control.users,
JSON_TABLE(merchant_access, '$[*]' COLUMNS (
merchant_access VARCHAR(32) PATH '$')
) t1
WHERE users.id = :userId
) AS t2
ON t1.merchantUuid = t2.merchant_access
WHERE t1.paymentType = 'RG'
AND t1.status = 1
) t3
ON t2.uuid = t3.uuid
WHERE t3.expDate BETWEEN DATE_SUB(CURDATE(), INTERVAL 30 DAY) AND DATE_ADD(CURDATE(), INTERVAL 30 DAY)
GROUP BY t2.holder, t2.bin, t2.last4Digits
ORDER BY t2.holder ASC", ['userId' => $request->userId]))
->when($request->search['holder'], function($q) use ($request) {
$q->where('t2.holder', 'LIKE', '%'.$request->search['holder'].'%');
})->get();
return $report;

How to convert SQL query to query builder?

controlens is a table in my database and entite, state are the fields of this table
SELECT a.entite, a.etat, COUNT(a.etat) as nombre_toperform, b.nombre_performed,c.nombre_incompatible
FROM `controlens` a
LEFT JOIN ( SELECT entite,COUNT(etat) as nombre_performed from `controlens` WHERE etat like 'PERFORMED' GROUP BY entite, etat) b on a.entite = b.entite
LEFT JOIN ( SELECT entite,COUNT(etat) as nombre_incompatible from `controlens` WHERE etat like 'INCOMPATIBLE' GROUP BY entite, etat) c on a.entite = c.entite
WHERE a.etat like '%TOPERFORM%'
GROUP BY a.entite, a.etat, b.nombre_performed,c.nombre_incompatible
There are likely few ways in which you can accomplish this. Here is one idea that might work (note: haven't fully tested, so it might need some tweaks):
$toPerform = '%TOPERFORM%';
$subQuery1 = 'SELECT entite,COUNT(etat) as nombre_performed from `controlens` WHERE etat like 'PERFORMED' GROUP BY entite, etat';
$subQuery2 = 'SELECT entite,COUNT(etat) as nombre_incompatible from `controlens` WHERE etat like 'INCOMPATIBLE' GROUP BY entite, etat';
DB::table('controlens as a')->select([
'a.entite',
'a.etat',
DB::raw('COUNT(a.etat) AS nombre_toperform'),
'b.nombre_performed',
'c.nombre_incompatible'
])
->leftJoin(DB::raw("($subQuery1) as b"), 'a.entite', '=', 'b.entite')
->leftJoin(DB::raw("($subQuery2) as c"), 'a.entite', '=', 'c.entite')
->where('a.etat', $toPerform)
->groupBy('a.entite', 'a.etat', 'b.nombre_performed', 'c.nombre_incompatible');
Alternatively, you could try this package to see if it helps the cause:
eloquent-subquery-magic
Beyond that, here are a few helpful articles that might point you in the correct direction:
subquery with join in
laravel
Laravel Fluent Query Builder Join with
subquery
How to write this (left join, subquery ) in Laravel
5.1?

Use SUMMARIZECOLUMNS on table union in DAX query

I am trying to write a DAX query that runs the SUMMARIZECOLUMNS function on a table variable. The table variable is the union of two tables that have the same columns in the same order.
When I try to run the query, I get a Cannot find table error. Here is the query I am trying to run:
EVALUATE
VAR u = UNION(Table1, Table2)
RETURN SUMMARIZECOLUMNS(u[CreationYear], u)
How can I run this query on the union of the two tables?
It's not very elegant, but in response to your comment on Marco's solution, you can do a count like this:
EVALUATE
VAR u = UNION(Table1, Table1)
RETURN SUMMARIZE(u, [CreationYear],
"Count",
COUNTX(
FILTER(u,
[CreationYear] = EARLIER([CreationYear])
),
[Id]
)
)
Try using SUMMARIZE in stead of SUMMARIZECOLUMNS. Like this:
EVALUATE
VAR u = UNION ( Table1, Table2 ) RETURN SUMMARIZE ( u, [CreationYear] )

Converting a raw query to Laravel query builder

I have the following MySQL query which fetches a list of the last 9 authors to write a post and lists them in order of the date of the last post they wrote.
It's working properly but I'd like to re-write it using the Laravel Query Builder. Here is the query at the moment:
$authors = DB::select("
SELECT
`a`.`id`,
`a`.`name`,
`a`.`avatar`,
`a`.`slug` AS `author_slug`,
`p`.`subheading`,
`p`.`title`,
`p`.`slug` AS `post_slug`,
`p`.`summary`,
`p`.`published_at`
FROM
`authors` AS `a`
JOIN
`posts` AS `p`
ON `p`.`id` =
(
SELECT `p2`.`id`
FROM `posts` AS `p2`
WHERE `p2`.`author_id` = `a`.`id`
ORDER BY `p2`.`published_at` DESC
LIMIT 1
)
WHERE
`a`.`online` = 1
ORDER BY
`published_at` DESC
LIMIT 9
");
I understand the basics of using the query builder, but there doesn't appear to be anything in the Laravel docs that allows for me to JOIN a table ON a SELECT.
Can anyone suggest a way that I can write this query using the Laravel Query builder, or perhaps suggest a way that I can rewrite this query to make it easier to structure with the query builder?
Try to do like this
$data = DB::table('authors')
->select(
'a.id',
'a.name',
'a.avatar',
'a.slug AS author_slug',
'p.subheading',
'p.title',
'p.slug AS post_slug',
'p.summary',
p.published_at')
->from('authors AS a')
->join('posts AS p', 'p.id', '=', DB::raw("
(
SELECT p2.id FROM posts AS p2
WHERE p2.author_id = b.id
ORDER BY p2.published_at
DESC LIMIT 1
)"))
->where('a.online', 1)
->limit(9)
->orderBy('p.published_at', 'desc')
->get();

Laravel 4.2 Eloquent using lists() with a join query

I have a query that makes use of multiple joins:
public function scopePurchased($query, $userId)
{
return $query
->join('products','characters.id','=','products.productable_id')
->join('bundle_product','bundle_product.product_id','=','products.id')
->join('bundles','bundles.id','=','bundle_product.bundle_id')
->join('purchases','purchases.bundle_id','=','bundles.id')
->join('users','purchases.user_id','=','users.id')
->whereNull('purchases.deleted_at')
->where('purchases.refunded', false)
->where('products.productable_type', '=', get_class($this))
->where('users.id','=',$userId)
->groupBy('characters.id')
->orderBy('characters.title', 'ASC');
}
And I want to retrieve an array of ID's from this query to use in another scope so:
$query->purchased($userID)->lists('id')
My initial thought was to use lists('id') which complained about an ambiguous query on the ID.
Column 'id' in field list is ambiguous
(
SQL: select `id` from `characters`
inner join `products` on `characters`.`id` = `products`.`productable_id`
inner join `bundle_product` on `bundle_product`.`product_id` = `products`.`id`
inner join `bundles` on `bundles`.`id` = `bundle_product`.`bundle_id`
inner join `purchases` on `purchases`.`bundle_id` = `bundles`.`id`
inner join `users` on `purchases`.`user_id` = `users`.`id`
where `characters`.`deleted_at` is null
and `purchases`.`deleted_at` is null
and `purchases`.`refunded` = 0
and `products`.`productable_type` = Character and `users`.`id` = 1
group by `characters`.`id`
order by `characters`.`title` asc
)
Makes sense, fair enough so I changed the lists to
$query->purchased($userID)->lists('characters.id')
Thinking that naming the table and column should fix it but finding that the lists function drops the 'character.' part and so having the same error.
It appear that lists may not use a dot notation, bring me to my question... Can I escape the dot notation or is there another way to get the list of ID's as an array?
Many thanks
You can alias the column name before using lists:
$query->purchased($userID)->select('characters.id as _id')->lists('_id');
This will avoid any column name conflicts.

Resources