left join with ActiveRecord (yii2) - activerecord

I tried to send SQL request with LEFT JOIN but it doesn't display data from table2 table.
public static function top($limit)
{
return self::findBySql("
SELECT * FROM table 1 g1
LEFT JOIN table2 s1
ON (g1.id = s1.g_id AND s1.id = (
SELECT MAX(id)
FROM table2 s2 WHERE s2.g_id = g1.id
))
LIMIT :limit",
[':limit' => $limit]
)->all();
}

It seems you are adding this function to the model and self represents the model itself.
Yii will not return results from another table and will be limited to the model only if you are calling the find on a model, instead you need to use a db query as below:
$query = new \yii\db\Query;
$query->select('*')
->from('table 1 g1')
->leftJoin('table2 s1', 's1.g_id AND s1.id = (SELECT MAX(id) FROM table2 s2 WHERE s2.g_id = g1.id')
->limit($Limit);
$command = $query->createCommand();
$resp = $command->queryAll();

The correct SQL query is
SELECT * FROM table 1 g1
LEFT JOIN table2 s1
ON g1.some_field = s1.some_field
where g1.some_field = s1.some_field are the fields that define the join.

I have working code something like...:)
with user and user_friend_list
$query = new Query;
$query ->select(['user.id AS user_id', 'user_friend_list.id'])
->from('user')
->innerJoin('user_friend_list', 'user.email = user_friend_list.email');
$command = $query->createCommand();
$data = $command->queryAll();
foreach($data as $datakey)
{
//echo $datakey['id'];
$friendfind = UserFriendList::findOne($datakey['id']);
$friendfind->is_app_using_user_id=$datakey['user_id'];
$friendfind->save();
}

Related

Which is the best efficient way to get many-to-many relation count in laravel?

I have students and subjects table in many-to-many relation (pivot table is student_subject).
Student Model
public function subjects()
{
return $this->belongsToMany(Subject::class, 'student_subject');
}
Subject Model
public function students()
{
return $this->belongsToMany(Student::class, 'student_subject');
}
Here I want the particular student subjects counts. I tried the below methods it's working fine but I want the best efficient way for this purpose.
1.
$student = Student::find($id);
$subject_count = $student->subjects()->count();
I checked the SQL query through laravel debuger it shows as below
select * from `students` where `students`.`id` = '10' limit 1
select count(*) as aggregate from `subjects` inner join `student_subject` on `subjects`.`id` = `student_subject`.`subject_id` where `student_subject`.`student_id` = 10 and `subjects`.`deleted_at` is null
$student = Student::withCount('subjects')->find($id);
$subject_count = $student->subjects_count;
I checked the SQL query through laravel debuger it shows as below
select `students`.*, (select count(*) from `subjects` inner join `student_subject` on `subjects`.`id` = `student_subject`.`subject_id` where `students`.`id` = `student_subject`.`student_id` and `subjects`.`deleted_at` is null) as `subjects_count` from `students` where `students`.`id` = '10' limit 1
$student = Student::find($id);
$subject_count = $student->loadCount('subjects')->subjects_count;
I checked the SQL query through laravel debuger it shows as below
select * from `students` where `students`.`id` = '10' limit 1
select `id`, (select count(*) from `subjects` inner join `student_subject` on `subjects`.`id` = `student_subject`.`subject_id` where `students`.`id` = `student_subject`.`student_id` and `subjects`.`deleted_at` is null) as `subjects_count` from `students` where `students`.`id` in (10)
$student = Student::find($id);
$subject_count = DB::table('student_subject')->where('student_id', $student->id)->count();
I checked the SQL query through laravel debuger it shows as below
select * from `students` where `students`.`id` = '10' limit 1
select count(*) as aggregate from `student_subject` where `student_id` = 10
According to the above ways which one is best and why? or if any different best way also there?
Doing relation()->count() is probably faster.
But if all you need is the count, withCount() should be better in terms of memory consumption.

How to convert Sql query to codeigniter Active Record

I have sql query as below, i need to convert sql to codeigniter active record.
select * from color c
left join (select pc.* from product_color pc
LEFT join product p on pc.product_id=p.product_id
WHERE p.product_id=1)x on c.id=x.color_id
In codeigniter you can get compiled query using get_compiled_select function.
Let's create inner query first.
$inner_query = $this->db->select('pc.*')
->from('product_color pc')
->join('product p','pc.product_id = p.product_id','left')
->where('p.product_id',1)
->get_compiled_select();
Now we will use inner query to create our final query.
$final_query = $this->db->select('*')
->from('color c')
->join("($inner_query) x",'c.id=x.color_id','left')
->get_compiled_select();
echo $final_query; die;
Try this into model file. and it's always better to keep sql keywords in capital.
$query = "SELECT * FROM color c
LEFT JOIN (SELECT pc.* FROM product_color pc
LEFT JOIN product p ON pc.product_id=p.product_id
WHERE p.product_id=1)x on c.id=x.color_id"
$query = $this->db->query($query);
$data = $query->result_array();

Inner Join in Codeigniter with multiple table

I wants to create a display function in crudodel of codeigniter to display records on Invoice no 13. I'd run the bellow Query on sql. Its working as per my requirement. Now I've to convert this Query in codeigniter using Inner Join.
SELECT b1.Invoice_No,
cust_name,
cust_address,
cust_contact,
Item_name,
Item_qty,
Item_amount
FROM tbl_bill_invoice AS b1
INNER JOIN tbl_billmenu AS b2 ON(b2.Invoice_No = b1.Invoice_No)
INNER JOIN tbl_billcustomer AS b3 ON(b3.cust_id = b1.cust_id)
WHERE b1.Invoice_no = 13
Try this
$this->db->select('b1.Invoice_No, cust_name, cust_address, cust_contact, Item_name, Item_qty, Item_amount');
$this->db->from(' tbl_bill_invoice as b1');
$this->db->join('tbl_billmenu as b2', 'b2.Invoice_No = b1.Invoice_No', 'inner');
$this->db->join('tbl_billcustomer as b3', 'b3.cust_id = b1.cust_id', 'inner');
$this->db->where('b1.Invoice_no', 13);
return $this->db->get()->row();
Take look,
$invoice_no = 13;
$this->db->select('b1.Invoice_No, cust_name, cust_address, cust_contact, Item_name, Item_qty, Item_amount');
$this->db->from('tbl_bill_invoice b1');
$this->db->join('tbl_billmenu b2', 'b2.Invoice_No = b1.Invoice_No', 'inner');
$this->db->join('tbl_billcustomer b3', 'b3.cust_id = b1.cust_id', 'inner');
$this->db->where('b1.Invoice_no', $invoice_no);
$query = $this->db->get();
if ($query->num_rows() > 0) {
return $query->row();
} else {
return array();
}
Simply write this
$sql = "SELECT b1.Invoice_No,
cust_name,
cust_address,
cust_contact,
Item_name,
Item_qty,
Item_amount
FROM tbl_bill_invoice AS b1
INNER JOIN tbl_billmenu AS b2 ON(b2.Invoice_No = b1.Invoice_No)
INNER JOIN tbl_billcustomer AS b3 ON(b3.cust_id = b1.cust_id)
WHERE b1.Invoice_no = 13";
$result = $this->db->query($sql)->result();

LINQ Left Join with use of Where Or syntax

How can I migrate this stored procedure into LINQ
DECLARE #customerIDs TABLE (customerID INT)
DECLARE #c INT
if (#customerName != '')
BEGIN
INSERT INTO #customerIDs
select id from customer
where name like '%' + #customerName + '%'
SELECT #c = COUNT(*) FROM #customerIDs
END
else
SET #c = 0
-- Insert statements for procedure here
SELECT DISTINCT l.*, dbo.GetListOfBranches(l.id) as 'list_of_branches', dbo.GetTopLevelCustomer(cid.customerID) FROM [login] l
LEFT JOIN login_to_customer ltc ON ltc.login_id = l.id
LEFT JOIN #customerIDs cid ON cid.customerID = ltc.customer_id
WHERE
(#c = 0 OR ltc.customer_id = cid.customerID) AND
(l.surname LIKE '%' + ISNULL(#surname, l.surname) + '%') AND
(l.forename LIKE '%' + ISNULL(#forename, l.forename) + '%') AND
(user_type = ISNULL(#userType, user_type)) AND
(l.active = ISNULL(#active, l.active))
ORDER BY surname ASC
I have got this so far:
List<Int32> customerIds = new List<int>();
if (!String.IsNullOrEmpty(customerName))
{
CustomerDataContext custDataContext = new CustomerDataContext();
customerIds = (from a in custDataContext.Customers
where a.name.Contains(customerName)
select a.id).ToList<Int32>();
}
LoginDataContext dataContext = new LoginDataContext();
var query = (from t in dataContext.logins
join t2 in dataContext.login_to_customers on t.id equals t2.login_id into a
from subquery in a.DefaultIfEmpty()
select new { t, listOfBranches = dataContext.GetListOfBranches(t.id), topLevelCustomer = dataContext.GetTopLevelCustomer(t.id) });
I need would then do a
if (customerIds.Count() > 0)
{
query = query.Where(a => customerIds.Contains(a.t.customer_id))
}
but as I need to perform the distinct I cant have the customer_id column in the query. Is there a way to include the
LEFT JOIN #customerIDs cid ON cid.customerID = ltc.customer_id
WHERE
(#c = 0 OR ltc.customer_id = cid.customerID)
Within the LINQ?
Thanks,
Richard

linq nested query

I have a query that has the following
var myvar = from table in MyDataModel
where.....
select new MyModel
{
modelvar1 = ...,
modelvar2 = (from..... into anothervar)
}
What I want to do is have modelvar2 be a join between the result I currently get from anothervar with another table in MyDataModel.
Thanks
The parenthesis looks more like a subquery than a join. This is how you do a join.
Example tables from the AdventureWorks database.
using (DataClasses1DataContext context = new DataClasses1DataContext())
{
// If you have foreign keys correctly in your database you can
// join implicitly with the "dot" notation.
var myvar = from prod in context.Products
where prod.ListPrice < 10
select new
{
Name = prod.Name,
Category = prod.ProductSubcategory.ProductCategory.Name,
};
// If you don't have foreign keys you need to express the join
// explicitly like this
var myvar2 = from prod in context.Products
join prodSubCategory in context.ProductSubcategories
on prod.ProductSubcategoryID equals prodSubCategory.ProductSubcategoryID
join prodCategory in context.ProductCategories
on prodSubCategory.ProductCategoryID equals prodCategory.ProductCategoryID
where prod.ListPrice < 10
select new
{
Name = prod.Name,
Category = prodCategory.Name,
};
// If you REALLY want to do a subquery, this is how to do that
var myvar3 = from prod in context.Products
where prod.ListPrice < 10
select new
{
Name = prod.Name,
Category = (from prodSubCategory in context.ProductSubcategories
join prodCategory in context.ProductCategories
on prodSubCategory.ProductCategoryID equals prodCategory.ProductCategoryID
select prodCategory.Name).First(),
};
// If you want to get a list from the subquery you can do like this
var myvar4 = from prodCategory in context.ProductCategories
select new
{
Name = prodCategory.Name,
Subcategoreis = (from prodSubCategory in context.ProductSubcategories
where prodSubCategory.ProductCategoryID == prodCategory.ProductCategoryID
select new { prodSubCategory.ProductSubcategoryID, prodSubCategory.Name }).ToList(),
};
}
SELECT [t0].[OrderID], [t0].[CustomerID], [t0].[EmployeeID], [t0].[OrderDate], [t0].[RequiredDate], [t0].[ShippedDate], [t0].[ShipVia], [t0].[Freight], [t0].[ShipName], [t0].[ShipAddress], [t0].[ShipCity], [t0].[ShipRegion], [t0].[ShipPostalCode], [t0].[ShipCountry]
FROM [Orders] AS [t0]
INNER JOIN ([Order Details] AS [t1]
INNER JOIN [Products] AS [t2] ON [t1].[ProductID] = [t2].[ProductID]) ON [t0].[OrderID] = [t1].[OrderID]
can be write as
from o in Orders
join od in (
from od in OrderDetails join p in Products on od.ProductID equals p.ProductID select od)
on o.OrderID equals od.OrderID
select o

Resources