MySql group by with where condition not working - mysql

I have 2 tables, groups and questions. I need the result in such a way that it contains group name and corresponding non-deleted question count.
The structure and data for the two tables are as afollows.
My expected Result is as follows
I tried the following code, but it gives the entire row including the deleted questions.
$groupname = DB::table('groups as d')
->select([
'd.id','d.group_name',DB::raw("count(dtls.survey_group_id) as count")
])
->leftJoin('questions as dtls','d.id', '=', 'dtls.survey_group_id')
->whereNotExists( function ($query) {
$query->select(DB::raw(1))
->from('questions')
->where('id', 'd.id')
->where('dtls.is_deleted', 1);
})
->groupBy('d.id','d.group_name')
->get()
->toArray();

A problem here is that ->where('id', 'd.id') mathches id with the literal string d.id which obviously is not what you want. In addition, inner query tables should be aliased to prevent ambiguity. You can try changing it to:
$groupname = DB::table('groups as d')
->select([
'd.id','d.group_name',DB::raw("count(dtls.survey_group_id) as count")
])
->leftJoin('questions as dtls','d.id', '=', 'dtls.survey_group_id')
->whereNotExists( function ($query) {
$query->select(DB::raw(1))
->from('questions as innerDtls')
->whereRaw('innerDtls.id = d.id')
->where('dtls.is_deleted', 1);
})
->groupBy('d.id','d.group_name')
->get()
->toArray();
Alternatively your current query can be simplified to:
$groupname = DB::table('groups as d')
->select([
'd.id','d.group_name',DB::raw("count(dtls.survey_group_id) as count")
])
->leftJoin('questions as dtls','d.id', '=', 'dtls.survey_group_id')
->where('dtls.is_deleted', 0)
->groupBy('d.id','d.group_name')
->get()
->toArray();

Related

Laravel. How to get a record, that has all user ids in related table?

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.

Laravel count with where on Query Builder with joins

Good day all, I am trying to count all records in a table but only if the table does not contain data in a specific column (deleted_at). It is a join table the table names are companies and employees. I am currently counting the records with a DB::raw but it should only count it if the deleted_at column is null. Please understand that i am a beginner.
public function index()
{
$user = Auth::user()->id;
$companies = DB::table('companies AS c')
->select([
'c.id',
'c.logo',
'c.company_name',
'c.created_at',
'c.sector',
'c.deleted_at',
DB::raw('COUNT(e.id) AS employee_count')
])
->leftJoin('employees AS e', 'e.company_id', '=', 'c.id' )
->leftJoin('company_user AS cu', 'cu.company_id', '=', 'c.id')
->where('cu.user_id', '=', $user)
->where('c.deleted_at', '=', null)
->groupBy('c.id')
->get();
return view('account.companies.index')
->with('companies', $companies);
}
If you are using Mysql then you could use conditional aggregation
$companies = DB::table('companies AS c')
->select([
'c.id',
'c.logo',
'c.company_name',
'c.created_at',
'c.sector',
'c.deleted_at',
DB::raw('SUM(c.deleted_at IS NULL) AS employee_count')
])
->leftJoin('employees AS e', 'e.company_id', '=', 'c.id' )
->leftJoin('company_user AS cu', 'cu.company_id', '=', 'c.id')
->where('cu.user_id', '=', $user)
->groupBy('c.id')
->get();
In mysql when an expression is used inside sum(a= b) it will result as a boolean 0/1 so you can get your conditional count using above
Or you could use whereNull() method in your query
->whereNull('c.deleted_at')
Use this code:
$employeeCount = DB::table('employees')
->select('companies.name', DB::raw('count(employees.id) as employee_count'))
->join('companies', 'employees.company','=','companies.id')
->groupBy('companies.id')
->get();

checking for multiple values in a single column in laravel 5

So I'm not sure whether I asked the question well. I'm new to laravel and right now I'm building an application where I need to fetch data for a user if certain conditions are met. This is what I'm trying to achieve:
Select from database where userid = $user and userstatus = active or inactive. or pending.
So all rows with the user id($user) and status(active, inactive and pending) will be returned.
I tried doing:
$users = DB::table('users')
->where('status', '=', 'active')
->orwhere('status', '=', 'inactive')
->orwhere('status', '=', 'pending')
->get();
This returned all the data in that particular table. What is the best way to go about this.
You have at least two options for how to do this you can use, including both so you have one for use in this case and one for general usage. Using a function in where creates a new block, so works like adding parentheses to your query
$users = DB::table('users')
->where('id', $user)
->where(function($query) {
$query->where('status', 'active')
->orWhere('status', 'inactive')
->orWhere('status', 'pending');
})->get();
or
$users = DB::table('users')->where('id', $user)->whereIn('status', ['active', 'inactive', 'pending'])->get();
You can do it as:
$users = DB::table('users')
->where('userid', $userid)
->whereIn('status',['active', 'inactive','pending'])
->get();

How to write a Laravel query to group duplicate records

This is my current query getting data from tables corporations, jobs, corp_networks and candidates.
$sqlCandSkills = DB::table('corporations')
->join('jobs', 'corporations.corp_id', '=', 'jobs.corp_id')
->join('corp_logos', 'corp_logos.corp_id', '=', 'corporations.corp_id')
->join('candidates', 'corporations.corp_id', '=', 'candidates.corp_id')
->join('corp_networks', 'corporations.corp_id', '=', 'corp_networks.participation_corp_id')
->where([
'corp_networks.owning_corp_id' => $this->corp->corp_id,
'corp_networks.status' => "Accepted"
])
->orwhere([
'corporations.corp_id' => $this->corp->corp_id
])
->where('candidates.is_available', '=', 0)->get();
I need to add a validation query into this because I'm getting multiple rows of same data from above query.
for($i=0 ; $i<sizeof($skillsArray); $i++){
$value= $skillsArray[$i];
echo($value);
$jobDetails = DB::select(
'SELECT * FROM jobs WHERE job_technical_requirements LIKE "%'.$value.'%" AND job_status = 1 INNER JOIN '
);
}
Above query gives all data but I also need to perform above checks.
I'm doing this second query to compare array of values to a csv values in column.
Now I need to achieve all this into a single result.
I need ways to do it either in sql query or laravel query.
you can use groupBy
$sqlCandSkills = DB::table('corporations')
->distinct()
->join('candidates', 'corporations.corp_id', '=', 'candidates.corp_id')
->join('corp_networks', 'corporations.corp_id', '=', 'corp_networks.participation_corp_id')
->where([
'corp_networks.owning_corp_id' => $this->corp->corp_id,
'corp_networks.status' => "Accepted"
])
->orwhere([
'corporations.corp_id' => $this->corp->corp_id
])
->where('candidates.is_available', '=', 0)
->groupBy(array(
'corporations.corp_id',
'corp_networks.participation_corp_id',
'corp_networks.owning_corp_id'
))
->get('corporations.corp_id');

WhereNotIn Subquery

What i'm trying to achieve is the following:
I want to check if there is a record with the same client_code but with a lower/different campaign id. I'm using a sub-query for now and i tried to do it with a join as well but I couldn't get the logic working
This is what i got now:
$oDB = DB::table('campaigns AS c')
->select(
'c.id AS campaign_id',
'cc.id AS campaign_customer_id'
)
->join('campaign_customers AS cc', 'cc.campaign_id', '=', 'c.id')
->where('c.status', '=', ModelCampaign::STATUS_PLANNED)
->where('c.scheduled', '=', 1)
->whereRaw('c.scheduled_at <= NOW()')
->where('cc.status', '=', ModelCampaignCustomer::STATUS_INVITE_EMAIL_SCHEDULED)
->whereNotIn('cc.client_code', '=', function ($query){
$query ->select(DB::raw(1))
->from('campaign_customers')
->whereRaw('campaign_id', '!=', 'c.id');
})
->where('cc.active', '=', 1)
;
any tips on how to work the logic would be great
You can use the ->toSql(); method to see the SQL so you can refactorize your query.
The whereNotIn probably shouldn't have an = in it
->whereNotIn('cc.client_code', function ($query){
....
edit
Try:
->whereNotIn('cc.client_code', function ($query){
$query->select(DB::raw('client_code'))
->from('campaign_customers')
->whereRaw('campaign_id != c.id');
})
I think the whereRaw should be a single text string or maybe you can use where here (looking at this for reference https://laravel.com/docs/5.2/queries#advanced-where-clauses). Also DB::raw(1) is going to return a 1 for each subquery result but you want an id for the whereNotIn.