I'm trying to sort comments. Each comment could have a parent_id in case it is a replay to another comment.
I need to order all the comments by parent_date and comment_date.
I have created this query:
$union = DB::table("press_comments as c2")
->select("c2.body", "c2.id", 'c2.parent_id', 'c2.created_at as ac', 'p.created_at as ap')
->join('press_comments as p', 'c2.parent_id', '=', 'p.id');
$comments = DB::table('press_comments as c1')
->select("c1.body", "c1.id", 'c1.parent_id', 'c1.created_at as ac', 'c1.created_at as ap')
// ->where("parent_id", "=", 0)
->union($union)
->orderBy("ap","asc")
->orderBy( "ac","asc")
->groupBy('id')
->paginate();
But I got too many lines: the groupBy seems not working on.
In plain mysql it works:
SELECT *
FROM ( SELECT c1.id,
c1.parent_id,
c1.created_at ac,
c1.created_at ap
FROM press_comments c1
UNION
SELECT c2.id,
c2.parent_id,
c2.created_at ac,
p.created_at ap
FROM press_comments c2
JOIN press_comments p
ON c2.parent_id = p.id) c
GROUP BY id
ORDER BY c.ap, c.ac;
What I'm missing in my Laravel query?
Related
I am new to Laravel and trying to support an existing application that is in Laravel 5. I am trying to convert the following SQL to eloquent structure
SELECT s.id,
CONCAT(u.first_name, ' ', u.last_name) AS user_name,
u.avatar_location AS user_img,
s.employee_photo,
d.name AS department,
seg.name AS segment,
s.survey_title,
s.before_action,
s.before_picture,
s.action,
s.action_date,
s.after_action,
s.after_picture,
s.nominated,
s.awarded,
s.created_at,
s.updated_at,
(SELECT COUNT(1) FROM likes l WHERE l.survey_id = s.id) AS likes,
(SELECT COUNT(1) FROM likes l WHERE l.survey_id = s.id AND l.user_id = 5) AS UserLikes,
(SELECT COUNT(1) FROM comments c WHERE c.survey_id = s.id ) AS comments
FROM surveys s
JOIN departments d
ON s.department = d.id
JOIN segments seg
ON s.segment_id = seg.id
JOIN users u
ON s.user_id = u.id
WHERE s.status = 'Approved'
ORDER BY s.action_date DESC
LIMIT 20 OFFSET 20
I know enough Laravel to know that my basic start would probably be
$surveys = DB::table('surveys')
->join('departments', 'surveys.department', '=', 'departments.id')
->join('segments', 'surveys.segment_id', '=', 'segments.id')
->join('users', 'surveys.user_id', '=', 'users.id')
->where('surveys.status', 'Approved')
->orderBy('surveys.action_date')
->skip(20)-take(20)
->select(...)->get();
However, I am not sure how to do the subqueries. Looking for any suggestions.
Thanks!
For select statements, you can use DB::raw().
$surveys = DB::table('surveys')
->join('departments', 'surveys.department', '=', 'departments.id')
->join('segments', 'surveys.segment_id', '=', 'segments.id')
->join('users', 'surveys.user_id', '=', 'users.id')
->where('surveys.status', 'Approved')
->orderBy('surveys.action_date')
->skip(20)-take(20)
->select([DB::raw('(SELECT COUNT(1) FROM likes l WHERE l.survey_id = s.id) AS likes'),
...
])
->get();
Similarly, select statements would go under the select array. Just so to be clear, the result will be a collection.
Im tried this to work it using Laravel Eloquent but i cant get exact query. So i make a raw query to get the data i want. Any one help me how to convert this into laravel eloquent or Query builder?
SELECT users.*,
chat.*
FROM users
LEFT JOIN
(SELECT a.customer_id,
a.time,
b.content
FROM
(SELECT customer_id,
MAX(datetimestamp) TIME
FROM chat_messages
GROUP BY customer_id) a
JOIN chat_messages b ON a.customer_id = b.customer_id
AND a.time = b.datetimestamp) chat ON users.id = chat.customer_id
WHERE users.customer_role != 0
ORDER BY TIME DESC
I think you are trying to get latest chat message for each user , your query can be rewritten using left join to pick the latest record per group and it would be easier to transform such query in laravel's query builder format
SQL
select u.*,c.*
from users u
join chat_messages c on u.id = c.customer_id
left join chat_messages c1 on c.customer_id = c1.customer_id and c.datetimestamp < c1.datetimestamp
where c1.customer_id is null
and u.customer_role != 0
order by c.datetimestamp desc
Query Builder
DB::table('users as u')
->select('u.*, c.*')
->join('chat_messages as c', 'u.id', '=', 'c.customer_id' )
->leftJoin('chat_messages as c1', function ($join) {
$join->on('c.customer_id', '=', 'c1.customer_id')
->whereRaw(DB::raw('c.datetimestamp < c1.datetimestamp'));
})
->whereNull('c1.customer_id')
->where('u.customer_role','!=',0)
->orderBy('c.datetimestamp', 'desc')
->get();
Reference:Laravel Eloquent select all rows with max created_at
I have the following SQL
SELECT C.CUOCODE, C.NAME, COUNT(*) TOTAL_PAYMENT, SUM(P.AMOUNT) TOTAL_AMOUNT
FROM TAX_PAYMENT P
INNER JOIN TAX_CHECKPOINT C ON C.CUOCODE = REGEXP_SUBSTR(P.INVOICEID, 'R....')
WHERE DELETED = 0 AND TO_CHAR(TXTIME,'YYYY-MM-DD') = '2018-04-24'
GROUP BY C.CUOCODE, C.NAME
ORDER BY TOTAL_AMOUNT DESC;
How can i convert to laravel eloquent, i have "Payment" model (table TAX_PAYMENT) with "paymentid" as primary key.
DB::table('TAX_PAYMENT as P')
->select([
'C.CUOCODE',
'C.NAME',
DB::raw('COUNT(*) AS TOTAL_PAYMENT'),
DB::raw('SUM(P.AMOUNT) AS TOTAL_AMOUNT'),
])->Join('TAX_CHECKPOINT C', 'C.CUOCODE', '=', DB::raw('REGEXP_SUBSTR(P.INVOICEID,'R....')'))
->where('DELETED', 0)
->where(DB::raw("TO_CHAR(TXTIME,'YYYY-MM-DD')"), '2018-04-24')
->groupBy('C.CUOCODE')
->groupBy('C.NAME')
->orderBy('TOTAL_AMOUNT', 'desc')
->toSql();
output
SELECT
`C`.`CUOCODE`,
`C`.`NAME`,
COUNT(*) AS TOTAL_PAYMENT,
SUM(P.AMOUNT) AS TOTAL_AMOUNT
FROM
`TAX_PAYMENT` AS `P`
INNER JOIN `TAX_CHECKPOINT C` ON `C`.`CUOCODE` = REGEXP_SUBSTR (P.INVOICEID,"R....")
WHERE
`DELETED` = ?
AND TO_CHAR (TXTIME, 'YYYY-MM-DD') = ?
GROUP BY
`C`.`CUOCODE`,
`C`.`NAME`
ORDER BY
`TOTAL_AMOUNT` DESC
A quick and dirty way would be to use Eloquents select raw like:
$result = DB::select( DB::raw("SELECT C.CUOCODE, C.NAME, COUNT(*)
TOTAL_PAYMENT, SUM(P.AMOUNT) TOTAL_AMOUNT FROM TAX_PAYMENT INNER JOIN
TAX_CHECKPOINT C ON C.CUOCODE
= REGEXP_SUBSTR(P.INVOICEID, 'R....') WHERE DELETED = 0 AND
TO_CHAR(TXTIME,'YYYY-MM-DD') = '2018-04-24' GROUP BY C.CUOCODE,
C.NAME ORDER BY TOTAL_AMOUNT DESC"));
I have 3 tables: Users, Properties, Units
User table:
user_id user_name
Properties table
pty_id pty_name user pty_status
Units Table
unit_id unit_name pty_id unit_status
i want to show user details , number of properties and units and their details.
Here is my query:
DB::statement('SET SESSION group_concat_max_len = 10485760');
$ar = DB::table('users as u')
->leftjoin('properties as p', function($join) {
$join->on('p.user_id', '=', 'u.user_id')->where('p.pty_status', '!=' ,0 );
})
->leftJoin(
DB::raw("
(select COALESCE(count(unit_id),0) AS cntunits, pty_id as temp_pty
from property_units as pu3
left join properties as p2 on pu3.unit_pty_id = p2.pty_id
where pu3.unit_status!=0
group by p2.pty_id) as temp"), 'p.pty_id', '=', 'temp.temp_pty')
->select(
DB::raw("group_concat(DISTINCT CONCAT(ej_p.pty_id,'|',ej_p.pty_name,'|',cntunits)) as pty_details"),
DB::raw("group_concat(DISTINCT CONCAT(ej_p.pty_id,'|',ej_p.pty_name)) as pty_details_copy")
)->paginate(10);
When I group_concat the unit_count, only those properties and units are concated where unit exists.
For example the above query returns the following result:
pty_details pty_details_copy
7|I2|2 7|I2, 22|tR ,51|SG APARTMENT,54_||_GA APARTMENTS,
Why properties with units (where unit count=0) are not binding? Where have I gone wrong?
EDIT
Here is the raw query:
select group_concat(DISTINCT CONCAT(p.pty_id,'|',p.pty_name,'|',cntunits)) as pty_details,
group_concat(DISTINCT CONCAT(p.pty_id,'|',p.pty_name)) as pty_details_copy
from users as u
left join properties as p on p.user_id = u.user_id and p.pty_status !=0
left join
(select COALESCE(count(unit_id),0) AS cntunits, pty_id as temp_pty
from property_units as pu3
left join properties as p2 on pu3.unit_pty_id = p2.pty_id
where pu3.unit_status!=0
group by p2.pty_id) as temp on p.pty_id = temp.temp_pty
As Solarflare suggested, i got the required result when I changed the query like this:
$ar = DB::table('users as u')
->leftjoin('properties as p', function($join) {
$join->on('p.user_id', '=', 'u.user_id')->where('p.pty_status', '!=' ,0 );
})
->leftJoin(
DB::raw("
(select COALESCE(count(unit_id),0) AS cntunits, pty_id as temp_pty
from property_units as pu3
left join properties as p2 on pu3.unit_pty_id = p2.pty_id
where pu3.unit_status!=0
group by p2.pty_id) as temp"), 'p.pty_id', '=', 'temp.temp_pty')
->select(
DB::raw("group_concat(DISTINCT CONCAT(ej_p.pty_id,'|',ej_p.pty_name,'|',coalesce(cntunits, 0))) as pty_details"))->paginate(10);
The WHERE from your first join should be part of the ON.
I'm now learning php and codeigniter and now I want to combine query to be fast and effective. I have made all, but haven't joined the last table...
I have 4 tables: posts, users, post_categories, categories;
And what I want to get:
All posts
User info using usr_id
Get all categories id from post_categories using cat_ids
And get each name of category using id_*
This is what I end up... it's not complete because I've got stuck with getting categories name for each of id_*
$data = $this->db->select('p.*, u.nickname, u.usr_status, u.usr_rating, pc.*')
->from('posts p')
->join('users u', 'p.usr_id = u.id', 'left')
->join('post_categories pc', 'p.cat_ids = pc.id', 'left')
->limit($limit, $start)
->order_by('p.id', 'desc')
->where('p.active', 1)
->get()
->result_array();
Anyone could help me to end up this query in codeigniter?
edit:
in post_categories: id_1 always will be... but id_2 and id_3 could stay as NULL(default value)
Something like the following SQL query should work for you...
SELECT
posts.*,
users.nickname, users.user_status, users.usr_rating,
c1.category as category_1,
c2.category as category_2,
c3.category as category_3
FROM posts
INNER JOIN users ON user.id = posts.user_id
INNER JOIN post_dategories ON post_categories.id = posts.cat_ids
INNER JOIN categories c1 ON post_categories.id_1 = c1.id
LEFT JOIN categories c2 ON post_categories.id_2 = c2.id
LEFT JOIN categories c3 ON post_categories.id_3 = c3.id
WHERE posts.active = 1
NOTE: LEFT JOIN on c2 and c3 because you said they were optional