I need to use subquery in from clause but i can not find such thing in Laravel docs
Laravel version 5.4
$sub = Chat::join("chats as _chats", function ($query) {
$query->on('chats.room_id', "=", "_chats.room_id")
->on('chats.user_type', "<>", "_chats.user_type")
->on('chats.created_at', "=", DB::raw("(SELECT MIN(created_at) FROM chats WHERE created_at > '_chats.created_at')"));
})
->selectRaw('TIMESTAMPDIFF(MINUTE, _chats.created_at, chats.created_at) as res')
->where('chats.user_type', 'pharmacy_consultant')
->where('chats.user_id', 26)
->toSql();
dd(
DB::connection('mysql2')
->table(DB::raw("({$sub}) as sub"))
->select('res')
->get()
);
(2/2) QueryException SQLSTATE[HY000]: General error: 2031
(SQL: select `res` from (select TIMESTAMPDIFF(MINUTE, _chats.created_at, chats.created_at) as res
from `chats` inner join `chats` as `_chats` on `chats`.`room_id` = `_chats`.`room_id` and `chats`.`user_type` <> `_chats`.`user_type` and `chats`.`created_at` =
(SELECT MIN(created_at) FROM chats WHERE created_at > _chats.created_at) where `chats`.`user_type` = ? and `chats`.`user_id` = ?) as sub)
Try passing the builder instance instead of the raw query.
// $sub = Query Builder instance
$sub = Chat::join("chats as _chats", function ($query) {
$query->on('chats.room_id', "=", "_chats.room_id")
->on('chats.user_type', "<>", "_chats.user_type")
->on('chats.created_at', "=", DB::raw("(SELECT MIN(created_at) FROM chats WHERE created_at > '_chats.created_at')"));
})
->selectRaw('TIMESTAMPDIFF(MINUTE, _chats.created_at, chats.created_at) as res')
->where('chats.user_type', 'pharmacy_consultant')
->where('chats.user_id', 26);
// ->toSql();
DB::connection('mysql2')
->table($sub, "sub")
->select('res')
->get()
Since you're not doing anything else than a select in your final query, why not just do that in the first query instead?
$results = Chat::join("chats as _chats", function ($query) {
$query->on('chats.room_id', "=", "_chats.room_id")
->on('chats.user_type', "<>", "_chats.user_type")
->on('chats.created_at', "=", DB::raw("(SELECT MIN(created_at) FROM chats WHERE created_at > '_chats.created_at')"));
})
->selectRaw('TIMESTAMPDIFF(MINUTE, _chats.created_at, chats.created_at) as res')
->where('chats.user_type', 'pharmacy_consultant')
->where('chats.user_id', 26)
->select('res')
->get();
Make it fit to your needs:
...
->addSelect([res' => ChartModel::select('//whatever')
->whereColumn('//sub-query column', 'parent-table.field')
->whereColumn('//and whatever')
->latest()
->take(1)
)]
...
Related
My query (DB::raw(AVG('pt.progress'))) this part is throwing error at the moment
$query = DB::table('projects as p')
->leftJoin('projects_tasks as pt','pt.project_id', 'p.id')
->select(
'p.id', 'p.project_name', DB::raw(AVG('pt.progress')) //this is where I need the average
);
$query->orderBy($order, $dir);
if ($limit != -1) {
$query->skip($start)->take($limit);
}
$records = $query->get();
Table structure:
projects:
========
id
project_name
...
...
projects_tasks:
===============
id
project_id,
parent, //0 or 1
progress //exmaple value 0.00 to 1.00
How to get the average of progress, where parent_id = 0 and project_id is the same?
The following query does work if I create a function and pass it in a loop, however, I want to optimize it and run it by joining on above query.
$data_row = DB::table('projects_tasks')
->select(DB::raw('(SUM(progress)*100)/count(progress) as project_progress'))
->where(['project_id' => $project_id, 'parent' => 0])
->get();
Seems that you have a syntax error on your query, the problem is in here DB::raw(AVG('pt.progress')).
Since you're using a raw query, the parameter there should be a string, so you must enclose that in quotes / double qoute.
$query = DB::table('projects as p')
->leftJoin('projects_tasks as pt','pt.project_id', 'p.id')
->select(
'p.id', 'p.project_name', DB::raw("AVG('pt.progress')")
);
$query->orderBy($order, $dir);
if ($limit != -1) {
$query->skip($start)->take($limit);
}
$records = $query->get();
There is a chat table and intermediate table.
I need to get from the chat table only those chats for which all user identifiers are found.
Now I am getting records if at least one match is found
My query
$chat = $this->select('chats.*')->distinct()
->rightJoin("chat_user", function ($query) {
$query->on("chats.id", "=", "chat_user.chat_id")
->whereIn("chat_user.user_id", [2, 17]);
})
->where('chats.type', '=', 'single')
->get();
Result
But I need a chat width id 4, because only it matches my request
I also tried to do it like this
$chat = $this->select('chats.*')->distinct()
->rightJoin("chat_user", function ($query) use ($members_ids) {
$query->on("chats.id", "=", "chat_user.chat_id")
->where("chat_user.user_id", 2)
->where("chat_user.user_id", 17);
})
->where('chats.type', '=', 'single')->get();
But result is empty
In plain SQL, this could be achieved with the following query:
SELECT chats.*
FROM chats
WHERE chats.type = 'single'
AND EXISTS (SELECT 1 FROM chat_user WHERE user_id = 2 AND chat_id = chats.id)
AND EXISTS (SELECT 1 FROM chat_user WHERE user_id = 7 AND chat_id = chats.id)
Translated into a Laravel query, we get the following:
$userIds = [2, 7];
$chats = DB::table('chats')
->where('chats.type', 'single')
->where(function (Builder $query) use ($userIds) {
foreach ($userIds as $userId) {
$query->whereExists(fn (Builder $query) => $query
->select(DB::raw(1))
->from('chat_user')
->where('chat_user.user_id', $userId)
->whereColumn('chat_user.chat_id', 'chats.id'));
}
})
->select('chats.*')
->get();
You should do something like this instead:
$chat = $this->select('chats.*')->distinct()
->rightJoin('chat_user', function ($query) {
$query->on('chats.id', '=', 'chat_user.chat_id')
->where('chat_user.user_id', 2)
->where('chat_user.user_id', 17);
})
->where('chats.type', '=', 'single')
->get();
Specifying multiple where works as an AND condition. If you use whereIn() will work as an OR conditions for the supplied values.
I have the following part of a larger elequent query, which all works when I'm not injecting a variable into DB::raw.
$tests->join('test_categories', function ($join) use($request) {
$join->on('test_categories.id', '=', DB::raw('(select category_id
from test_category
join test_categories on test_category.category_id = test_categories.id
where test_category.test_id = tests.id
and test_categories.name = ?
limit 1)', ['Cars']
));
});
But when the SQL executes it amends the '?' to 4, as in:
and test_categories.name = 4
Rather than being the expected:
and test_categories.name = 'Cars'
Any help would be appreciated.
UPDATED
I also tried the following before:
$tests->join('test_categories', function ($join) use ($category) {
$join->on('test_categories.id', '=', DB::raw("(select category_id
from test_category
join test_categories on test_category.category_id = test_categories.id
where test_category.test_id = tests.id
and test_categories.name = :category
limit 1)",array('category' => $category)));
});
But in the query, this just outputs the following:
and test_categories.name = :category
This comes with a "SQLSTATE[HY093]: Invalid parameter number: mixed named and positional parameters" error.
Still the same issue.
And another variation which tries the same technique with the $join->on function.
$tests->join('test_categories', function ($join) use ($category) {
$join->on('test_categories.id', '=', DB::raw("(select category_id
from test_category
join test_categories on test_category.category_id = test_categories.id
where test_category.test_id = tests.id
and test_categories.name = :category
limit 1)"),array('category' => $category));
});
This results in an ErrorException (E_NOTICE) Array to string conversion:
protected function compileWheresToArray($query)
{
return collect($query->wheres)->map(function ($where) use ($query) {
return $where['boolean'].' '.$this->{"where{$where['type']}"}($query, $where);
})->all();
}
Based on this link you could use
$results = DB::select( DB::raw("SELECT * FROM some_table WHERE some_col = :somevariable"), array(
'somevariable' => $someVariable,
));
Try replacing :category with ".$category.".
Not sure if it's a good practice to do it this way but it should work.
$tests->join('test_categories', function ($join) use ($category) {
$join->on('test_categories.id', '=', DB::raw("(select category_id
from test_category
join test_categories on test_category.category_id = test_categories.id
where test_category.test_id = tests.id
and test_categories.name = ".$category."
limit 1)"));
});
This is my base query:
$base_query = TableOne::join('table_two as p1', 'p1.order_id', '=', 'table_ones.id')
->join('table_threes as j1', 'p1.id', '=', 'j1.partner_order_id')
->select('table_ones.*')
->groupBy('table_ones.id', 'j1.status');
When someone need to filter some data like partner_id on table_two table, we add some extra column like this,
$base_query->where(function ($query) {
$query->whereNull('p1.cancelled_at');
$query->orWhere('p1.cancelled_at', '=', DB::select(DB::raw("SELECT MAX(p2.cancelled_at) FROM partner_orders p2 WHERE p2.order_id = p1.order_id")));
$query->whereNotExists(function ($query) {
DB::select(DB::raw("SELECT * FROM partner_orders p3 WHERE p3.order_id = p1.order_id AND p3.cancelled_at IS NULL"));
});
});
But after run this query, their is an error
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'p1.order_id'
in 'where clause' (SQL: SELECT MAX(p2.cancelled_at) FROM
partner_orders p2 WHERE p2.order_id = p1.order_id)
i think, their is some issue on that query.
$base_query->where(function ($query) {
$query->whereNull('p1.cancelled_at');
$query->orWhere('p1.cancelled_at', '=', DB::select(DB::raw("SELECT MAX(p2.cancelled_at) FROM partner_orders p2 WHERE p2.order_id = p1.order_id")));
$query->whereNotExists(function ($query) {
DB::select(DB::raw("SELECT * FROM partner_orders p3 WHERE
p3.order_id = p1.order_id AND p3.cancelled_at IS NULL"));
});
});
`
DB::select() directly executes the query.
In the case of orWhere(), only use a raw expression.
$query->orWhere('p1.cancelled_at', '=', DB::raw("(SELECT MAX(p2.cancelled_at) [...])"));
In the case of whereNotExists(), use whereRaw():
$query->whereRaw("NOT EXISTS(SELECT * [...])");
In both cases, you can also use a closure and build the query manually:
$query->orWhere('p1.cancelled_at', '=', function($query) {
$query->from('partner_orders')->select([...])->where([...]);
})
$query->whereNotExists(function($query) {
$query->from('partner_orders as p3')->where([...]);
})
SELECT *
FROM `events`
WHERE (`customer_bookable` = 1 and template = 1 )
OR (`customer_bookable` = 0 and template = 0 )
and (`start_date_time` BETWEEN '2017-09-01 00:00:00' and '2017-09-21 00:00:00')
And (profile_id = 10)
and (event_live_status = 1)
and (class != 0)
and (privacy_status = 1)
Do you need help with the 'or' part? You can use closures where you would use parenthesis in SQL:
...
->where( function ($query) {
$query->where('customer_bookable',1)
->where('template',1);
})->orWhere( function ($query) {
$query->where('customer_bookable',0)
->where('template',0);
})
...
Your query may look like this,
$events = DB::('events')
->where( function ($query) {
$query->where('customer_bookable',1)
->where('template',1)
->orWhere('customer_bookable',0)
->orWhere('template',0);
})
->where( function ($query) {
$query->whereBetween('start_date_time',['2017-09-01 00:00:00' and '2017-09-21 00:00:00'])
->where('profile_id',10)
->where('event_live_status',1)
->where('class','!=',0)
->where('privacy_status',1);
});