generate mysql query from relations using via or viaTable relations - yii

consider the below example...
class Customers extends ActiveRecord
{
public function getOrders()
{
return $this->hasMany(Orders::className(), ['customer_id' => 'id']);
}
public function getOrderItems()
{
return $this->hasMany(OrderItems::className(), ['order_id' => 'id'])
->via('orders');
}
}
how i can generate any one of the follwing query from the getOrderItems() relation
SELECT * FROM `order-items`
LEFT JOIN `orders` ON `orders`.`id` = `order-items`.`order_id`
LEFT JOIN `customers` ON `customer`.`id` = `orders`.`customer_id`
OR
SELECT `order-items`.* FROM `order-items`,`orders`,`customers`
WHERE `customer`.`id` = `orders`.`customer_id` AND `orders`.`id` = `order-items`.`order_id`
OR
SELECT * FROM `order-items` WHERE `order_id` IN(
SELECT * FROM `orders` WHERE `customer_id` IN(
SELECT * FROM `customers`
)
)
i use the following code to do this.
$customers = Customers::findAll();
$query = $customers[0]->getOrderItems()->createCommand()->rawSql;
but it only generates
SELECT * FROM `order-items`
What to do...???

use this :
$q = Customers::findAll()->innerJoinWith('orderItems')->createCommand()->rawSql;
you have to use relation name like this not as function

Related

How do i convert this SQL to Entity Framework LINQ query

Can someone help me convert this SQL Query to EntityFramework LINQ?
DECLARE #UserId varchar(50) = '123'
SELECT
TL.TrackId,
COUNT(*) AS LikeCount,
(SELECT IIF(COUNT(*) > 0, 'true','false') FROM UserTrackLikes WHERE
UserId = #UserId AND TrackId = TL.TrackId) AS IsLiked
FROM TrackList AS TL
LEFT OUTER JOIN UserTrackLikes AS UTL
ON UTL.TrackId = TL.TrackId
GROUP BY TL.TrackId
You can use the query syntax:
int userId = 123;
var result = (from trackList in context.TrackLists
select new
{
trackList.TrackId,
LikeCount = trackList.Likes.Count(),
IsLiked = trackList.Likes.Any(x => x.UserId == userId)
}).ToList();
Assuming that here, Likes is a collection of UserTrackLike, declared like this:
public ICollection<UserTrackLike> Likes { get; set; }

select some ids from sql in linq

hi I'm using the query below to select studentId and Score from table1 now i want select users that i selected their ids from table2, how i can select it with ids?
i can select users with this query from v in dc.tbl_Students select v but i want select some users that i have their id.
var qBestMan = (from T in (((from tbl_ActPoints in dc.tbl_ActPoints
select new
{
StudentId = (int?)tbl_ActPoints.StudentId,
Score = (int?)tbl_ActPoints.Score
}).Concat(
from tbl_EvaPoints in dc.tbl_EvaPoints
select new
{
StudentId = (int?)tbl_EvaPoints.StudentId,
Score = (int?)tbl_EvaPoints.Score
})))
group T by new
{
T.StudentId
} into g
orderby g.Sum(p => p.Score) descending
select new
{
g.Key.StudentId,
HighScoreUser = g.Sum(p => p.Score)
}).ToArray();
Try something like this:
//qBestMan must be a List, or a IEnumarable and not a Array. Remove the .ToArray() at the end, or substitute it by .ToList()
var Result = from users in dc.tbl_Students
join bestMen in qBestMan on bestMen.StudentId equals users.userid
select new
{
//fields that you want
example = users.example,
other = bestMen.other
};

Entity Framework join query with int array

i have got 3 tables on my database.
---Student---
id - name
---Language---
id - lang
---StudentLanguage---(Common Table)
id - studentId - langId
Students can have more languages. i want to search students with an int[] array values. But not with IN() - Contains(), it must be with and - && operator and this operator take int[] values.
in sql =
`select t1.id, t1.name from Student t1 join StudentLanguage t2
ON(t1.id=t2.studentId) where (t2.langId=1 and t2.langId=3 and t2.langId=5);`
so how can i do this query with Entity Framework? (...where new int[] { 1,3,5 })
This code generate some clumsy sql query...
int[] ids = new[] { 1, 3, 5 };
var acc = from st in db.Students select st;
foreach (var id in ids)
{
int id1 = id;
var res =
from st in db.Students
from lng in st.Language
where lng.Id == id1
select st;
acc =
from a in acc
join st in res on a.Id equals st.Id
select a;
}
acc.ToList();
... sql query :
SELECT
[Extent1].[Id] AS [Id],
[Extent1].[Name] AS [Name]
FROM [dbo].[Student] AS [Extent1]
INNER JOIN [dbo].[StudentLanguage] AS [Extent2] ON [Extent1].[Id] = [Extent2].[Student_Id]
INNER JOIN [dbo].[StudentLanguage] AS [Extent3] ON [Extent1].[Id] = [Extent3].[Student_Id]
INNER JOIN [dbo].[StudentLanguage] AS [Extent4] ON [Extent1].[Id] = [Extent4].[Student_Id]
WHERE ([Extent2].[Language_Id] = #p__linq__0)
AND ([Extent3].[Language_Id] = #p__linq__1)
AND ([Extent4].[Language_Id] = #p__linq__2)
List<int> langIds = new int[] { 1, 3, 5 }.ToList();
var c = langIds.Count;
var res2 = _context.Students
.Where(x => x.StudentLanguages
.Where(l => langIds.Contains(l.langId)).Select(y => y.langId).Distinct().Count() >= c);
result SQL:
SELECT [t0].[id], [t0].[name]
FROM [dbo].[Student] AS [t0]
WHERE ((
SELECT COUNT(*)
FROM (
SELECT DISTINCT [t1].[langId]
FROM [dbo].[StudentLanguage] AS [t1]
WHERE ([t1].[langId] IN (1, 3, 5)) AND ([t1].[studentId] = [t0].[id])
) AS [t2]
)) >= 3
Use Distinct if StudentLanguages theoretically may have several overlapping bundles StudentId - LangId.
Try something like this...
resultArr = [];
For(int i = 0; i<arr.length; i++) {
var result = db.Student.Where(s=>s.StudentLanguage.langId == arr[i]);
resultArr.append(result);
}
var db = new MyDbContext();
var langIds = new[] { 1, 3, 5 };
IEnumerable<Student> student = from st in db.student select st;
foreach (var item in langIds)
{
student = student.Join(db.StudentLanguage.Where(w => w.langId == item),
st => st.studentId,
stMap => stMap.id,
(st, stMap) => new { Student= stMap, StudentLanguage = st})
.Select(x => x.Student).Distinct();
}
i can do this like that. Maybe foreach can be turn linq and this code can be only one line and a little short.
I try to search how to do it and here is what i come out with:
int[] langIds = new int[] { 1, 3, 5 };
var lang = _context.Languages.Where(x => langIds.Contains(x.id));
var result = _context.Students.Where(x => !lang
.Except(x.StudentLanguages
.Select(y => y.Language)
.Intersect(lang)).Any());
Here i use Except and Intersect linqToSQL extension methods.
It produces this SQL statement:
SELECT [t0].[id], [t0].[name]
FROM [dbo].[Student] AS [t0]
WHERE NOT (EXISTS(
SELECT NULL AS [EMPTY]
FROM (
SELECT DISTINCT [t1].[id], [t1].[name]
FROM [dbo].[Language] AS [t1]
WHERE (NOT (EXISTS(
SELECT NULL AS [EMPTY]
FROM (
SELECT DISTINCT [t3].[id], [t3].[name]
FROM [dbo].[StudentLanguage] AS [t2]
INNER JOIN [dbo].[Language] AS [t3] ON [t3].[id] = [t2].[langId]
WHERE (EXISTS(
SELECT NULL AS [EMPTY]
FROM [dbo].[Language] AS [t4]
WHERE ([t3].[id] = [t4].[id]) AND ([t4].[id] IN (#p0, #p1, #p2))
)) AND ([t2].[studentId] = [t0].[id])
) AS [t5]
WHERE [t1].[id] = [t5].[id]
))) AND ([t1].[id] IN (#p3, #p4, #p5))
) AS [t6]
))
Note that i populate languages from database. Unfortunatly you can not use local collections in your query since LinqToSQL don't know how to translate them into SQL. If you do the same thing with local int array or any other collection you will get this exception:
LINQ To SQL exception: Local sequence cannot be used in LINQ to SQL
implementation of query operators except the Contains operator

Yii2: How to use orWhere in andWhere

I want create this query with yii2 search model
select * from t1 where (title = 'keyword' or content = 'keyword') AND
(category_id = 10 or term_id = 10 )
But I don't know how to use orFilterWhere and andFilterWhere.
My code in search model:
public function search($params) {
$query = App::find();
//...
if ($this->keyword) {
$query->orFilterWhere(['like', 'keyword', $this->keyword])
->orFilterWhere(['like', 'content', $this->keyword])
}
if ($this->cat) {
$query->orFilterWhere(['category_id'=> $this->cat])
->orFilterWhere(['term_id'=> $this->cat])
}
//...
}
But it creates this query:
select * from t1 where title = 'keyword' or content = 'keyword' or
category_id = 10 or term_id = 10
First, your required sql statement should be something like this:
select *
from t1
where ((title LIKE '%keyword%') or (content LIKE '%keyword%'))
AND ((category_id = 10) or (term_id = 10))
So your query builder should be something like this:
public function search($params) {
$query = App::find();
...
if ($this->keyword) {
$query->andFilterWhere(['or',
['like','title',$this->keyword],
['like','content',$this->keyword]]);
}
if ($this->cat) {
$query->andFilterWhere(['or',
['category_id'=> $this->cat],
['term_id'=> $this->cat]]);
}...

Need Linq equivalent

Help in find the Linq equivalent on the below sql query:
select sum(weight) from (
select weight from pers p
join list l on l.persindex= p.persindex
group by p.persindex,weight) a
from p in context.pers
join l in context.list on l.persindex equals p.persindex
group by new
{ p.persindex,
l.weight
} into myGroup
select new()
{ Key = myGroup.Key,
GroupSum = myGroup.sum(x=>x.weight)
}
I guess that's what you need:
public int CalcWeight(IEnumerable<Person> pers, IEnumerable<Person> list)
{
return
pers
.Join(list, p=>p.PersIndex, l=>l.PersIndex, (p, l) => new {p.PersIndex, l.Weight})
.GroupBy( a => new {a.PersIndex, a.Weight})
.Sum(group=>group.Key.Weight);
}
Data class Person is decalerd like this:
public class Person
{
public int PersIndex;
public int Weight;
}
VB.NET version
Dim customerList = From p In pers
Group Join l In list On
p.persindex Equals l.persindex
Into joineddata = Group,
TotalOweight = Sum(p.weight)
Select p.persindex, TotalOweight
Try : Linquer SQL to LINQ convertion tool :
from p in pers
joins l in list on l.persindex equals p.persindex
group by new {p.persindex,l.weight } into grp
select new { sum = grp.sum(x=>x.weight)}