Select clause inside IN with TypeORM - sql

I have a pretty simple sql query:
select * from comments c
inner join users u on u.id = c.user_id
where user_id = 1 OR (c.user_id IN (select user_id_one from friends f where user_id_two = 1))
I am having a lot of trouble getting this translated into TypeORM, specifically this part:
c.user_id IN (select user_id_one from friends f where user_id_two = 1)
No where is it clear on how to use the IN operator along with a inner select statement.

You can add a Where statement and inside that add something like this:
query.where((queryBuilder: SelectQueryBuilder<YOUR_ENTITY>) => {
queryBuilder.where('alias.id in' +
queryBuilder.subQuery()
.select('a.id')
.from(YOUR_ENTITY, 'a')
.getQuery(),
)
})
// ...

Related

How do I optimize this DB2 Query Where Clause?

I've got a query here that looks for users authorized to a project and it's written in a way that is human readable, however I'm looking to optimize a DB2 query. Is it possible to utilize some nested selects or some clever joining of tables to make this query perform better?
SELECT *
FROM PROJECT p, USER_EMAIL_ACCESS uea, USER_EMAIL e
WHERE (
uea.PROJECT_ID = p.ID and
uea.USER_EMAIL_ID = l.ID and
uea.STATE_ID = 1 and
e.USER_ID = 100 and
e.STATE_ID = 1 and
p.STATE_ID = 1
)
try this :
SELECT *
FROM
PROJECT p
inner join USER_EMAIL_ACCESS uea on (uea.PROJECT_ID, uea.STATE_ID) = (p.ID, p.STATE_ID)
inner join USER_EMAIL e on e.STATE_ID = uea.STATE_ID and e.USER_ID = 100
WHERE p.STATE_ID = 1

How to use subquery in the join function of Yii framework 2 ActiveRecord?

Below is my pure SQL query.
SELECT a.*, b.*
FROM a
INNER JOIN b
ON a.id = b.a_id
INNER JOIN (
SELECT a_id, MAX(add_time) AS max_add_time
FROM b
GROUP BY a_id
) m
ON b.a_id = m.a_id AND b.add_time = m.max_add_time
ORDER BY b.add_time DESC
I have the subquery in the second INNER JOIN. Below my active query.
$subQuery = B::find()->select(['a_id', 'MAX(add_time) AS max_add_time'])->groupBy('a_id');
$query = A::find()->innerJoin('b', 'a.id = b.a_id')
->innerJoin('(' .
$subQuery->prepare(Yii::$app->db->queryBuilder)
->createCommand()
->rawSql
. ') m', 'b.a_id = m.a_id AND a.add_time = m.max_add_time ')
->orderBy('b.add_time DESC');
It works fine, but I do not like the way I use the subquery in the second INNER JOIN. What I want to approach with this query is to select the left table inner join with right table, group by a_id and order by the add_time (DESC) of the right table. How should I better use the subquery in the second INNER JOIN?
The snippet below is untested but it should be something like that. If you read the docs (at http://www.yiiframework.com/doc-2.0/yii-db-query.html#innerJoin()-detail) you can see an array with a subquery is also valid input, with the key being the alias.
$subQuery = B::find()
->select(['a_id', 'MAX(add_time) AS max_add_time'])
->groupBy('a_id');
$query = A::find()
->innerJoin('b', 'a.id = b.a_id')
->innerJoin(['m' => $subQuery], 'b.a_id = m.a_id AND a.add_time = m.max_add_time')
->orderBy('b.add_time DESC');
Having created the join, if you need to use any of the columns returned by the subQuery, you need to add properties to the Yii2 model class, e.g.
$subQuery = FinancialTransaction::find()
->select( new \yii\db\Expression( 'SUM(amount) as owing') )
->addSelect('booking_id')
->groupBy('booking_id');
$query = $query
->addSelect(['b.*', 'owing'])
->leftJoin(['ft' => $subQuery], 'b.booking_display_id = ft.booking_id');
To access "owing" the model has to have the property (PHPdoc optional):
/**
* #var float
*/
public $owing=0;

Nested WHERE IN clause SQL to LINQ

I have a nested WHERE IN clause in my SQL, how would this translate to LINQ, bonus points for using lambda expressions. New to all of this.
SELECT EndowmentID
FROM Criteria c
WHERE c.ID IN(
SELECT CriterionID
FROM Filters
WHERE ChoiceID IN(
SELECT ChoiceID
FROM Responses
WHERE ApplicationID = 1
)
)
This query can definitely be improved using joins...
SELECT EndowmentID
FROM
Criteria C
JOIN Filters F ON C.ID = F.CriterionID
JOIN Responses R ON F.ChoiceID = R.ChoiceID
WHERE R.ApplicationID = 1
Depending on the keys of your tables you might have to SELECT DISTINCT
From there you can write a simple LINQ query:
from c in Criteria
join f in Filters on c.ID equals f.CriterionID
join r in Responses on f.ChoiceID equals r.ChoiceID
where r.ApplicationID = 1
select c.EndowmentID
Again, you might have to Distinct() this.
var result =
Criteria.Where(c =>
Filters.Where(f =>
Responses.Where(r => r.ApplicationId == 1).Select(r => r.ChoiceId)
.Contains(f.ChoiceId)
).Select(f => f.CriterionId)
.Contains(c.Id)
).Select(c => EndowmentId);

"WHERE" Statement From Another Table

I have a table of following/followers that has 3 fields:
id , FollowingUserName,FollowedUserName
And I have a table with posts:
id,Post,PublishingUsername
And I need a query which returns certain fields from post
but the "where" will be where:
The PublishingUsernam From The Posts Will Match The FollowedUserName From The Following/Followers Table
And The FollowingUserName Will Be The Logged On UserName.
To just get posts:
select p.* from posts p where p.PublishingUsername in
(select FollowedUsername from followers)
and p.PublishingUsername = LOGGEDINUSER
Or you could use a join:
select p.* from posts p
left join followers f on f.PublishingUsername = p.PublishingUsername
and p.publishingUsername = LOGGENINUSER
You're looking to do a JOIN it looks like. Basically, you want to select from your post table where the publishing username = followed user name, and where followingusername = loggedin name.
Just taking a stab (since I don't have an SQL server here right now), but it might look like:
SELECT * FROM Posts INNER JOIN Following ON Posts.PublishingUsername = Following.FollowedUserName WHERE FollowingUserName = LoggedInName
Without JOIN you can:
SELECT * FROM Posts p, Followers f
WHERE
f.FollowingUserName = 'LoggedInUserName'
AND f.FollowedUserName = p.PublishingUsername
Using cleaner Join Syntax
SELECT *
FROM following f
JOIN posts p ON p.PublishingUsername = f.FollowedUsername
AND f.FollowingUserName = LOGGED_IN;
SELECT 'fields'
FROM TABLE1 INNER JOIN TABLE2
ON TABLE1.FollowedUserName = TABLE2.PublishingUsername
WHERE FollowingUserName = 'myvalue'

Error in SQL to LINQ conversion, how to solve that?

I have a SQl query working fine, I need to convert it to LINQ and got some problems.
My working SQL query:
select d.UserID, d.Content, d.UpdateTime
from DiaryPosts as d
where d.UserID = 2
/* friends */
Union
select d.UserID, d.Content, d.UpdateTime
from DiaryPosts as d
join Friends as fr
on d.UserID = fr.FriendID
where fr.UserID = 2
/* following */
Union
select d.UserID, d.Content, d.UpdateTime
from DiaryPosts as d
join Followers as fl
on d.UserID = fl.UserID
where fl.FollowerID = 2
/* ordenando por UpdateTime desc */
order by 3 desc
What I tried based on my own previous question:
var friends = (from u in db.User
join f in db.Friends
on u.ID equals f.FriendID
where f.UserID == userset.ID
orderby u.Nickname
select new FriendsSet { ID = u.ID, Nickname = u.Nickname, Thumbnail = u.Thumbnail }).ToList();
var followers = (from u in db.User
join f in db.Followers
on u.ID equals f.FollowerID
where f.UserID == userset.ID
orderby u.Nickname
select new FriendsSet { ID = u.ID, Nickname = u.Nickname }).ToList();
var diaryPosts = (from d in db.DiaryPosts
join e in db.EstadosDeAlma
on d.EstadosDeAlmaID equals e.ID
join u in db.User
on d.UserID equals u.ID
where d.UserID == userset.ID
select new DiaryPostsSet {
PostID = d.ID,
EstadoDeAlmaID = e.ID,
EstadoDeAlma = e.Title,
Author = u.Nickname,
Thumbnail = u.Thumbnail,
UserID = u.ID,
IsDuplicated = d.IsDuplicated,
FriendID = d.FriendID,
FriendName = u.Nickname,
Time = d.UpdateTime,
MessagesCount = d.FriendMessages.Count(m => m.DiaryPostsID == d.ID)
}).Take(6).ToList();
var diaryPostsUnion = diaryPosts.Union(friends).Union(followers).OrderBy(d => d.UpdateTime);
The errors I get:
'System.Collections.Generic.List<MvcWebRole1.Models.DiaryPostsSet>' does not contain a definition for 'Union' and the best extension method overload 'System.Linq.ParallelEnumerable.Union<TSource>(System.Linq.ParallelQuery<TSource>, System.Collections.Generic.IEnumerable<TSource>)' has some invalid arguments
Instance argument: cannot convert from 'System.Collections.Generic.List<MvcWebRole1.Models.DiaryPostsSet>' to 'System.Linq.ParallelQuery<MvcWebRole1.Models.FriendsSet>'
You're trying to union a sequence of one type with a sequence of another type. That doesn't make sense - unions have to be over the same types, basically.
It's not really clear what you're trying to do here, but I suspect you don't want a union.
Oh, and if you want all of this to happen in the database, get rid of the ToList calls.
EDIT: Okay, it's hard to see exactly how your LINQ queries correspond to your SQL queries, but basically your "select" clauses should be something like:
from d in db.DiaryPosts
// stuff here
select new { UserID = d.ID, d.UpdateTime, d.Content }
Use the exact same anonymous type in each query - the same property names and types, in the same order - and you should be able to use the Union method.