Join multiple tables used as Indexing - Laravel - sql

I have three tables - Chairman, Designation, Members.
MY requirement is to map the member to chairman and assign member a role.
I was able to fetch the list of members under the chairman when I had chairman_id and designation_id in the members table.
Since the chairman change, most of the members stay intact. So I came up with an idea of indexing them
Table - membermap
id | chairman_id | designation_id | member_id
So the list is preserved how many chairmans come and go. I dont need to create new profile for new chairman rather than map to it.
I am now sure how do I do it,
So far I was able to pull the ID but I am not sure how do I join the tables
Tables
Chairman
id| name
Designation
id|designation
Members
id|members
Here is my controller
$mapmember = Statechairman::findOrFail($id)->statechairmembersmap;
dd($mapmember);
In this Iam getting the statechairmembersmap but it's fetching all the result and not limiting the match.
I also tried to join the query using the DB
$mapmember = DB::table('statechairmen')
->join('state_chairman_members_maps', 'state_chairman_members_maps.chairman_id','statechairmen.id')
->join('statemembers','statemembers.id','state_chairman_members_maps.members_id')
->select('state_chairman_members_maps.*')->get();
but this result show me the Table - membermap but not the other results.
My Models:
Chairman :
public function statechairmembersmap(){
return $this->hasMany('App\StateChairmanMembersMap','chairman_id','id');
}
public function statemembers(){
return $this->hasMany('App\Statemembers','chairman_id', 'id');
}
public function statedesignation(){
return $this->hasMany('App\Statedesignation','id','designation_id');
}
membermap:
protected $table = 'state_chairman_members_maps';
protected $dates = ['deleted_at'];
public function statechairman(){
return $this->belongsTo('App\Statechairman','id');
}
public function statedesignations(){
return $this->belongsTo('App\Statedesignation','designation_id','id');
}
public function statemembers(){
return $this->belongsTo('App\Statemembers','members_id','id');
}
Please assist me where I doing wrong.

Thanks a lot for checking the question out.
Finally after a lot of strugle, I was able to find it by myself.
$mapmembers = DB::table('state_chairman_members_maps')
->join('statechairmen','statechairmen.id','=','state_chairman_members_maps.chairman_id')
->join('statemembers','statemembers.id','=','state_chairman_members_maps.members_id')
->join('statedesignations','statedesignations.id','=','state_chairman_members_maps.designation_id')
->where('chairman_id','=',$id)
->get();
Here is what I came up with.
Here I have joined 3 tables and mapped the id comming from the chairman to filter the result. I getting the results.

Related

Convert Query to Eloquent

How to make that query with eloquent
SELECT employees.first_name, companies.name FROM employees
JOIN companies ON employees.company_id = companies.id
My relationships
public function employees()
{
return $this->hasMany(Employee::class);
}
public function company()
{
return $this->belongsTo(Company::class);
}
I fetching the name with a given ID, but how can I find it for all. Or maybe I am thinking wrong
$employee = $employee->all()->find($id)->company->name;
I assumed your employees Model name as Employee and companies Model name as Company
$employees = Employee::with('company')->get();
if(!empty($employees)){
foreach($employees as $employee){
echo $employee->first_name;
echo $employee->company->name;
}
}
If you want to search per id then you may do as below.
$employee = Employee::with('company')->find($id);
echo $employee->company->name;
$employee = Employee::where('employees.id',$id)
->join('companies','companies.id','=','employees.company_id')
->select('employees.first_name', 'companies.name')
->first();
Firs Of all this is very bad practice:
$employee = $employee->all()->find($id)->company->name;
This returns all employee collection and then searches id in it. You can simply use Employee::find($id)
Now about your query, as I guess your company model has many employee and if you want to find all company employees you have to do like that:
$company->employees()->select('first_name')->get(); // Collection of Employee
If you want to get specific company employee with employee id you can do:
$company->employees()->select('first_name')->where('id', $id)->first(); // null or Employee

symfony (doctrine): DQL query, how to exclude results?

I have very basic knowledge of SQL and don't how to modify my query so it returns the expected result.
My entities Activity has a field members (a manyToMany relation). An activity can be done by several members.
I want to select all the activities a specific member does NOT take part into. I know the member's id (my variable $selfId).
Here's what I'm doing in ActivityRepository:
public function getCollectiveActivities($selfId)
{
$qb = $this->createQueryBuilder('a');
$qb->join('a.members', 'm')
->where('m.id != :selfId')
->setParameter('selfId', $selfId);
return $qb
->getQuery()
->getResult();
}
My problem: when an activity "owns" two or more members, if one of them has $selfId as id, this activity ends up in my query results.
But since one of the members of this activity has the id $selfId, it should not be returned. What am I doing wrong?
EDIT
I think I need to be more restrictive, I just don't know how.
Let's say I have two activities:
activity1 which is owned by member1 and member2
activity2 which is owned by member3 and member4
$selfId = 3 (this means I don't want to fetch activities owned by member3)
From what I understand, the join clause might return lines like these:
activity1 | memberId: 1 (different from selfId = 3 so activity1 will be fetched)
activity1 | memberId: 2 (different from selfId = 3 so activity1 will be fetched)
activity2 | memberId: 3 (= selfId so activity2 shouldn't be fetched)
activity2 | memberId: 4 (different from selfId = 3 so activity2 WILL be fetched. PROBLEM???)
EDIT 2
Others already faced the same problem and found this solution and this one, but they seem a bit hacky. Any clue on how to improve them would be welcome.
You have to specifically select the results you want to be hydrated. The problem you're seeing is that you're just selecting activity.
Then when you call $activity->getMembers() members are lazy loaded, and this doesn't take into account your query.
You can avoid this like so:
public function getCollectiveActivities($selfId)
{
$qb = $this->createQueryBuilder('a');
$qb->addSelect('m');
$qb->join('a.members', 'm')
->where('m.id != :selfId')
->setParameter('selfId', $selfId);
return $qb
->getQuery()
->getResult();
}
This means your fetched activity will already have its members hydrated and restricted by your query condition.
I ended up adapting a solution posted by #NtskX.
public function getCollectiveActivities($selfId)
{
$qbMyCollectives = $this->createQueryBuilder('ca');
$qbMyCollectives
->select('ca.id')
->leftJoin('ca.members', 'm')
->where('m.id = :selfId')
->setParameter('selfId', $selfId);
$qb = $this->createQueryBuilder('a');
$qb
->where($qb->expr()->notIn('a.id', $qbMyCollectives->getDQL()))
->setParameter('selfId', $selfId); // I had to declare the parameter one more time
return $qb
->getQuery()
->getResult();
}
I really thought someone would show up with a better way to do the join, so any other answer is much welcome.
public function getCollectiveActivities($selfId)
{
return $this->createQueryBuilder('a')
->join('a.members', 'm')
->where($qb->expr()->neq('c.selfId', $selfId))
->getQuery()
->getResult();
}

Simple SQL to Eloquent Query (Laravel)

I have two tables: users (Users) and groups (Groups).
Users
-----------------
id | username | group
1 | Bob | 2
Groups
-----------------
id | name
1 | firstgroup
2 | secondgroup
I would like to display: users.ID, users.username, group.name (1, Bob, secondgroup)
An SQL statement like so would work:
SELECT Users.id, Users.username, Groups.name
FROM Users
INNER JOIN
Groups ON Groups.id = Users.group
However, I'm struggling to write this in Eloquent, since there is no "FROM". At the moment I'm going for something along the lines of the below, using JOINS (http://laravel.com/docs/queries#joins)
$users = Users::select('id','username', 'Groups.name')->joins('Groups.id', '=', 'id')->get();
Now this isn't working - I think the joins has to come before the select but I just can't work it out :(
I think you're confusing a few things here...
You're mixing Eloquent with the lower-level DB::table('foo')->select() syntax. When you want to use Eloquent I suggest you take a look at the docs about relationships in Eloquent.
You should define your models like so:
class User extends Eloquent {
public function group()
{
return $this->belongsTo('Group', 'group');
// second parameter is necessary because you didnt
// name the column "group_id" but simply "group"
}
}
class Group extends Eloquent {
public function users()
{
return $this->hasMany('User', 'group');
}
}
This sets up all the joins you might be needing later. You can then simply use User::with('group')->all(); and have the query built and run for you.
Database: Query Builder(DB) is not a Eloquent(ORM):
Database query builder you have to inform the table names and the fields, like it says on in your related link of laravel docs: "...provides a convenient, fluent interface to creating and running database queries." like these query below:
$users = DB::table('users')
->join('contacts', 'users.id', '=', 'contacts.user_id')
->join('orders', 'users.id', '=', 'orders.user_id')
->select('users.*', 'contacts.phone', 'orders.price')
->get();
Eloquent is a ORM - Object related Mapping, it means that your class User is related to the table users (look at you files Migrations) and this class extends the Model Class, thus you can access the methods like these bellow:
class User extends Models
{
public static function usersWithGroups(){
return User::select('id', 'name', 'email')->with('groups')->get();
}
}
Observe that method is into the class User, so you can access that in a static way "User::", using Eloquent you'll have many hidden static methods that will improve you time codding, because you are inheriting de Model methods, to more details visit the Eloquent Docs at: Eloquent Docs

Convert multi-rows values into Collection(List) in LINQ

I am struggling with converting multi-rows values which are belong to the same user into collection.
Here is a simple scenario.
users Table:userid, password
address Table:address, userid
Users Table and Address Table are one-to-many related--one user might have multi-addresses.
Assume the User's ID is 1001 while he/she have two addresses one is in Auckland and another one is Wellington.
I would like select both of them together with user's id.
1001 Auckland
1001 Wellington
So the question is are there any approach is able to put these two value into collection like list.
public class UserDetails{
private List<String> _Address
public string userid{get;set;}
public List<String> Address{
get{retrun _Address;}
set{_Address=value;}
}
}
var user_address= from _user in users
join _address in address on _user.userid=_address.userid
select new userDetails{
userid=_user.userid
**Address.add()**
};
Does anyone know how to construct the List in the LINQ and call the add method.
I want to put the list object into one row so that avoid the redundancy of userid.
Thanks for your help.
Maybe something like this:
var user_address= from _user in users
select new userDetails{
userid=_user.userid,
Address=(from _address in address
where _user.userid=_address.userid
select _address.:address
).ToList()
};
You do not have to join the address table.

Simple Linq-to-entities query involving .Include I believe

I have a Linq-to-Entities query that is not complicated but requires an .include and/or projection and/or join because it must be executed in one pass.
Here is my database (Microsoft SQL Server 2008):
Table A (Customers) (contains CustomerID (customer IDs), and ZipCode (zip codes) as strings.
Table C (Categories) (contains CategoryID (categories) like "food", "shelter","clothing", "housing" (primary keys).
Table A_C is a linking table, since Tables A and C are linked as many-to-many: contains just two fields: CustomerID "customer IDs" and CategoryID (Categories), in combination as primary keys. This table is a linking table betweeen tables A and C.
Here is my query, that must be executed in just one trip to the database: I need to select all records in Table A that satisfy a condition, then filter these records depending on a 'list of parameters' that are found in the linking Table A_C--and do this all in one trip to the database. But I don't know what the length or composition of the list of parameters for Table A_C is, ahead of time--it varies from call to call. Thus this list of parameters varies method call by method call.
To give a more concrete example:
Table A has a list of customer IDs. I find the customers that live in a certain Zip code. Then, in the same SQL query, I need to find which of these customers have selected certain categories: Food, Clothing, Housing, etc, but my web method does not know ahead of time what these categories are, rather, they are passed as a list to the method: List myCategoryList (which could be 1 category or 100 categories, and varies method call by method call).
How do I write the projection using Linq-to-Entities? When the list of parameters varies? And do it all in one pass?
List<string> CategoryList = new List<string>() { "Food", "Shelter", "Housing" }; // in one call to the web service method
List<string> CategoryList = new List<string>() { "Food", "Clothing" }; //could be a second call--it varies and I don't know ahead of time what the List will be
So how can I do the SQL query using Linq-to-Entities? In one pass? (Of course I could loop through the list, and make repeated trips to the database, but that's not an optimal solution I am told). Projection,.Include are keywords but surfing the net yielded nothing.
Here is a crude guess, just to get ball rolling:
public void WebMethod1 (CategoryList)
{
using (EntityFramework1 context = new EntityFramework1())
{
/* assume CategoryList is a list of strings passed into the method and is,for this particular call,something like: List<string> CategoryList = new List<string>() { "Food", "Clothing" }; for this call, but in the next call it could be: List<string> CategoryList = new List<string>() { "Food", "Shelter", "Housing" } */
string ZipCodeString = "12345";
string customerIDString = "E12RJ55";
var CustomersFromZipCodeHavingSelectedCertainCategories = from x in context.A_C
where x.A.CustomerID == customerIDString
where x.A.StartsWith(ZipCodeString)
where x.A_C.Contains(CategoryList) //???? This is clearly not grammatical, but what is?
select x;
}
/*
my problem is: I want to filter all records from A that contain a zipcode 12345, and that also have a certain CustomerID "E12RJ55" from table A, but further filter this set with all such CustomerIDs in linking table A_C that contain the categories "Food" and "Clothing".
How to do this in one pass? I can do this quite easily in multiple passes and trips to the database using code, but somebody in this thread here http://bit.ly/rEG2AM suggested I do a Join/projection and do it all in one fell swoop.
*/
I will also accept SQL answers since it might help yield a solution. This question btw is not difficult I believe--but I could not find an answer on the net.
EDIT: with answer and credit to david s.
I thank you for the answer david.s. Here is what worked, slightly different than the answer by david.s, in that I am using the linking table (bridge table) called “Customer_Categories” that is between the table Customer and Categories and contains the primary key of each (as is required for many-to-many relationships). This bridge table is what I called "A_C" in my original answer, and here has ints rather than strings but is the same thing. Intellisense picked up this table and I used it, and it works. Also keep in mind that CategoryList is a list of ints, List CategoryList = new List();, yet amazingly it automagically works inside this SQL-to-Entities query:
Var CustomersFromZipCOde = context.Customers.Where (custo => custo.CustomerID==customerIDString && custo.ZipCode.StartsWith(ZipCodeString) && custo.Customer_Categories.Any(categ => CategoryList.Contains(categ.CategoryID)));
//gives the right output, incredible.
First of all i would like to say that even if you explanation is very long it is not very clear. You would like a simple Linq-to-Entities query but you don't give the Entities, you only speak of tables in your database.
Assuming you have the following entities:
public class Customer
{
public string CustomerID { get; set; }
public string ZipCode { get; set; }
public virtual ICollection<Category> Categories { get; set; }
}
public class Category
{
public string CategoryID { get; set; }
public virtual ICollection<Customer> Customers { get; set; }
}
Your query might look like this:
var CustomersFromZipCodeHavingSelectedCertainCategories =
context.Customers.Where(
customer => customer.CustomerID == customerIDString &&
customer.ZipCode.StartsWith(ZipCodeString) &&
customer.Categories.Any(
category => CategoryList.Contains(category.CategoryID));
More info on other ways to do this here:
http://smehrozalam.wordpress.com/2010/06/29/entity-framework-queries-involving-many-to-many-relationship-tables/