Laravel subquery query - sql

I want to use subquery in query as select. But this code doesnt work.
$listed_waiting_approach = DB::table('be_medical_insurance_for_foreigners')
->join('be_product','be_product.id','=','be_medical_insurance_for_foreigners.product_id')
->join('be_status','be_status.id','=','be_medical_insurance_for_foreigners.payment_status_id')
->where('be_medical_insurance_for_foreigners.is_approved','=',false)
->where('be_medical_insurance_for_foreigners.is_active','=',true)
->where('be_medical_insurance_for_foreigners.payment_status_id','=',$payment_status_id1)
->where('be_medical_insurance_for_foreigners.order_status_id','=',$order_status_id1)
->select('be_medical_insurance_for_foreigners.*','be_product.name as productname','be_medical_insurance_for_foreigners.is_approved as approve','be_status.code as statuscode','**(SELECT code FROM be_status WHERE id=$payment_status_id1 ) as paymentname**')
->get();

You can use a DB::raw combine with a DB::select. That is something like
DB::select( DB::raw( " ... ") )

You can also use selectRaw:
DB::table('be_medical_insurance_for_foreigners')
->selectRaw("be_medical_insurance_for_foreigners.*, be_product.name as productname, be_medical_insurance_for_foreigners.is_approved as approve, be_status.code as statuscode, (SELECT code FROM be_status WHERE id={$payment_status_id1}) as paymentname")
->get();

Related

SQL request with GROUP BY and SUM in Eloquent

I just want make a simple sql request in my laravel application.
I'm not very comfortable with Eloquent aha.
This is the SQL request I want to make with eloquent :
select user_id, project_id, sum(hours)
FROM time_entries
WHERE spent_on BETWEEN '2018-04-10' AND '2018-12-10'
GROUP BY user_id, project_id
I've been trying something like :
TimeEntries::whereBetween('spent_on', [($request->input('debut')), ($request->input('fin'))])->groupBy('user_id')->sum('hours');
(but you can see it's hopeless)
Use selectRaw().
TimeEntries::whereBetween('spent_on', [($request->input('debut')), ($request->input('fin'))])->groupBy(['user_id', 'project_id'])->selectRaw('user_id , project_id, sum(hours) as sum')->get();
You can use the selectRaw function of Eloquent,
like this:
TimeEntries::selectRaw('user_id, project_id, sum(hours)')
->whereBetween(
'spent_on',
[ ($request->input('debut')), ($request->input('fin')) ]
)
->groupBy('user_id', 'project_id');
But be aware that not to binding variables in the selectRaw string parameter, it might cause SQL injection problem since it by-pass the escaping check
Below query will work:
$query = TimeEntries::query();
$query->selectRaw('user_id', 'project_id', sum(hours))
->whereRaw("spent_on >= '2018-04-10' and spent_on <= '2018-12-10'")
->groupBy('user_id')
->groupBy('project_id');
$result = $query->get();
Model->select(DB::raw('user_id, project_id,
SUM(hours)')->whereBetween...

How to convert SQL Query to CodeIgniter?

How to convert this query :
SELECT pembelian_detail_tb.kode_beli, pembelian_detail_tb.kode_produk, produk_tb.nama, pembelian_detail_tb.jumlah
FROM pembelian_detail_tb
INNER JOIN produk_tb ON pembelian_detail_tb.kode_produk = produk_tb.kode_produk;
I have try many code, and i still got undefine.
Try this
$query = $this->db->select('pembelian_detail_tb.kode_beli, pembelian_detail_tb.kode_produk, produk_tb.nama, pembelian_detail_tb.jumlah')
->from('pembelian_detail_tb')
->join('produk_tb', 'pembelian_detail_tb.kode_produk = produk_tb.kode_produk', 'inner')
->get();
I like to use Query Bindings once a join is involved in a query:
https://www.codeigniter.com/userguide3/database/queries.html
search page for "query bindings"
this escapes values for you of course and if you need to debug dump $this->db->last_query();

Use SQL query in Laravel

this is my sql Query:
SELECT DISTINCT batch_job_instance.JOB_NAME, MAX(batch_job_execution.CREATE_TIME) AS CREATED_TIME, batch_job_execution.END_TIME, batch_job_execution.STATUS FROM `batch_job_execution` INNER JOIN batch_job_instance ON batch_job_execution.JOB_INSTANCE_ID = batch_job_instance.JOB_INSTANCE_ID WHERE batch_job_execution.CREATE_TIME LIKE '%2016-12-05%' GROUP BY batch_job_instance.JOB_INSTANCE_ID ORDER BY MAX(batch_job_execution.CREATE_TIME) DESC
my Question, how i use that query in laravel? i am new in laravel, can someone help me? i need this for my project Thanks :)
You can run this SQL query as ot is if you had problem in converting in laravel format.
You can use :
DB::select(DB::RAW(your_sql_query)):
Hope this will help.
You can create a function within your model and query the data using the bellow format
public static function getJobs()
{
$jobs = DB::table('batch_job_execution')
->select(
DB::raw('
DISTINCT batch_job_instance.JOB_NAME,
MAX(batch_job_execution.CREATE_TIME) AS CREATED_TIME,
batch_job_execution.END_TIME,
batch_job_execution.STATUS
'
)
)
->join('batch_job_instance', 'batch_job_execution.JOB_INSTANCE_ID', '=', 'batch_job_instance.JOB_INSTANCE_ID')
->where('batch_job_execution', 'LIKE', '%2016-12-05%')
->groupBy('batch_job_instance.JOB_INSTANCE_ID')
->orderBy(DB::raw('MAX(batch_job_execution.CREATE_TIME)'),'DESC')
->get();
// ->toSql();
return $jobs;
}

How to select from subquery using Laravel Query Builder?

I'd like to get value by the following SQL using Eloquent ORM.
- SQL
SELECT COUNT(*) FROM
(SELECT * FROM abc GROUP BY col1) AS a;
Then I considered the following.
- Code
$sql = Abc::from('abc AS a')->groupBy('col1')->toSql();
$num = Abc::from(\DB::raw($sql))->count();
print $num;
I'm looking for a better solution.
Please tell me simplest solution.
In addition to #delmadord's answer and your comments:
Currently there is no method to create subquery in FROM clause, so you need to manually use raw statement, then, if necessary, you will merge all the bindings:
$sub = Abc::where(..)->groupBy(..); // Eloquent Builder instance
$count = DB::table( DB::raw("({$sub->toSql()}) as sub") )
->mergeBindings($sub->getQuery()) // you need to get underlying Query Builder
->count();
Mind that you need to merge bindings in correct order. If you have other bound clauses, you must put them after mergeBindings:
$count = DB::table( DB::raw("({$sub->toSql()}) as sub") )
// ->where(..) wrong
->mergeBindings($sub->getQuery()) // you need to get underlying Query Builder
// ->where(..) correct
->count();
Laravel v5.6.12 (2018-03-14) added fromSub() and fromRaw() methods to query builder (#23476).
The accepted answer is correct but can be simplified into:
DB::query()->fromSub(function ($query) {
$query->from('abc')->groupBy('col1');
}, 'a')->count();
The above snippet produces the following SQL:
select count(*) as aggregate from (select * from `abc` group by `col1`) as `a`
The solution of #JarekTkaczyk it is exactly what I was looking for. The only thing I miss is how to do it when you are using
DB::table() queries. In this case, this is how I do it:
$other = DB::table( DB::raw("({$sub->toSql()}) as sub") )->select(
'something',
DB::raw('sum( qty ) as qty'),
'foo',
'bar'
);
$other->mergeBindings( $sub );
$other->groupBy('something');
$other->groupBy('foo');
$other->groupBy('bar');
print $other->toSql();
$other->get();
Special atention how to make the mergeBindings without using the getQuery() method
From laravel 5.5 there is a dedicated method for subqueries and you can use it like this:
Abc::selectSub(function($q) {
$q->select('*')->groupBy('col1');
}, 'a')->count('a.*');
or
Abc::selectSub(Abc::select('*')->groupBy('col1'), 'a')->count('a.*');
There are many readable ways to do these kinds of queries at the moment (Laravel 8).
// option 1: DB::table(Closure, alias) for subquery
$count = DB::table(function ($sub) {
$sub->from('abc')
->groupBy('col1');
}, 'a')
->count();
// option 2: DB::table(Builder, alias) for subquery
$sub = DB::table('abc')->groupBy('col1');
$count = DB::table($sub, 'a')->count();
// option 3: DB::query()->from(Closure, alias)
$count = DB::query()
->from(function ($sub) {
$sub->from('abc')
->groupBy('col1')
}, 'a')
->count();
// option 4: DB::query()->from(Builder, alias)
$sub = DB::table('abc')->groupBy('col1');
$count = DB::query()->from($sub, 'a')->count();
For such small subqueries, you could even try fitting them in a single line with PHP 7.4's short closures but this approach can be harder to mantain.
$count = DB::table(fn($sub) => $sub->from('abc')->groupBy('col1'), 'a')->count();
Note that I'm using count() instead of explicitly writing the count(*) statement and using get() or first() for the results (which you can easily do by replacing count() with selectRaw(count(*))->first()).
The reason for this is simple: It returns the number instead of an object with an awkwardly named property (count(*) unless you used an alias in the query)
Which looks better?
// using count() in the builder
echo $count;
// using selectRaw('count(*)')->first() in the builder
echo $count->{'count(*)'};
Correct way described in this answer: https://stackoverflow.com/a/52772444/2519714
Most popular answer at current moment is not totally correct.
This way https://stackoverflow.com/a/24838367/2519714 is not correct in some cases like: sub select has where bindings, then joining table to sub select, then other wheres added to all query. For example query:
select * from (select * from t1 where col1 = ?) join t2 on col1 = col2 and col3 = ? where t2.col4 = ?
To make this query you will write code like:
$subQuery = DB::query()->from('t1')->where('t1.col1', 'val1');
$query = DB::query()->from(DB::raw('('. $subQuery->toSql() . ') AS subquery'))
->mergeBindings($subQuery->getBindings());
$query->join('t2', function(JoinClause $join) {
$join->on('subquery.col1', 't2.col2');
$join->where('t2.col3', 'val3');
})->where('t2.col4', 'val4');
During executing this query, his method $query->getBindings() will return bindings in incorrect order like ['val3', 'val1', 'val4'] in this case instead correct ['val1', 'val3', 'val4'] for raw sql described above.
One more time correct way to do this:
$subQuery = DB::query()->from('t1')->where('t1.col1', 'val1');
$query = DB::query()->fromSub($subQuery, 'subquery');
$query->join('t2', function(JoinClause $join) {
$join->on('subquery.col1', 't2.col2');
$join->where('t2.col3', 'val3');
})->where('t2.col4', 'val4');
Also bindings will be automatically and correctly merged to new query.
I like doing something like this:
Message::select('*')
->from(DB::raw("( SELECT * FROM `messages`
WHERE `to_id` = ".Auth::id()." AND `isseen` = 0
GROUP BY `from_id` asc) as `sub`"))
->count();
It's not very elegant, but it's simple.
This works fine
$q1 = DB::table('tableA')->groupBy('col');
$data = DB::table(DB::raw("({$q1->toSql()}) as sub"))->mergeBindings($q1)->get();
I could not made your code to do the desired query, the AS is an alias only for the table abc, not for the derived table.
Laravel Query Builder does not implicitly support derived table aliases, DB::raw is most likely needed for this.
The most straight solution I could came up with is almost identical to yours, however produces the query as you asked for:
$sql = Abc::groupBy('col1')->toSql();
$count = DB::table(DB::raw("($sql) AS a"))->count();
The produced query is
select count(*) as aggregate from (select * from `abc` group by `col1`) AS a;
->selectRaw('your subquery as somefield')
Deriving off mpskovvang's answer, here is what it would look like using eloquent model. (I tried updating mpskovvang answer to include this, but there's too many edit requests for it.)
$qry = Abc::where('col2', 'value')->groupBy('col1')->selectRaw('1');
$num = Abc::from($qry, 'q1')->count();
print $num;
Produces...
SELECT COUNT(*) as aggregate FROM (SELECT 1 FROM Abc WHERE col2='value' GROUP BY col1) as q1

Select distinct value count laravel

I have an orders table where there is a status column.
I am trying to get the count of each status like this :
$pending = Order::where('status','=','pending')->count();
$active = Order::where('status','=','active')->count();
But this is not efficient as am having to make one call for each status type.
How can I reduce number of queries ?
To make an SQL request:
SELECT count(DISTINCT `status_id`) FROM `dbname`.orders WHERE `user_id` = '2';
In Laravel you can try the following:
$user->orders()->distinct()->count(["status_id"]);
You could try
$orders = Order::select(DB::raw('count(*) as order_count, status'))
->groupBy('status')
->get();
here is the way you write ->
$users= DB::table('table_name')->distinct()->get(['column_name']);
$users_count = $users->count();