How to perform left outer join with distinct clause - linq-to-sql

I have the following data:
Users:
Id UserId Name
----------------
1 1 Him
2 10 Her
3 2 Other
Groups:
Id GroupId UserId
-------------------
1 1 1
2 2 2
3 3 10
In SQL I can do something like this to determine if a user is in any group
select *
from Users as u
left outer join (select distinct(UserId) from Groups) as g on u.UserId = g.UserId
The result should be something like this.
Id UserId Name UserId
------------------------
1 1 Him 1
2 10 Her 10
3 2 Other Null
But how can I do this in LINQ?

I think that this one is helpful for u,
var data = (from u in Users
join g in Groups.Where(a => a.UserId == (from gp in Groups.Select(r=>r.UserId).Distinct() ) )
on u.UserId equals g.UserId into outer
from x in outer.DefaultIfEmpty()
select u);

In function syntax, it would look like
var result = Users.Join(Groups,
U => U.UserId, G => G.GroupId,
(U,R) => R.Select(
G => new { Id = U.Id, UserId = U.UserId, Name = U.Name, UserId = G.UserId }
).DefaultIfEmpty(new { Id = U.Id, UserId = U.UserId, Name = U.Name, UserId = null })
);

Related

MySql query on 3 different tables

I have 3 tables.
Owners:
ownerID name
1 josh
Pets:
petID name
1 M
2 x
3 f
4 h
PetsOwners:
petID ownerID
1 1
3 1
4 1
I have a query that returns the ownerID from a person. "SELECT ownerID FROM Owners WHERE name = 'josh';" This will return ownerID = 1. I need a query that returns all pets that josh owns. In this case will be "m", "f" and "h" according to the petsOwners table.
If you have ownerId use
SELECT p.name
FROM Pets p
JOIN PetsOwners po
ON p.petID = po.petID
WHERE po.ownerID = 1
If you only have the owner name, need join all 3 tables
SELECT p.name
FROM Pets p
JOIN PetsOwners po
ON p.petID = po.petID
JOIN Owners o
ON po.ownerID = o.ownerID
WHERE o.name = 'josh'
If you just want their names:
SELECT Pets.name
FROM Pets, PetsOwners, Owners
WHERE Pets.petID = PetsOwners.petID
AND Owners.ownerID = PetsOwners.ownerID;
try this:
select a.ownerID,a.`name`as OwnerName, b.petID,b.`name` as PetName from
(select ownerID `name` from Owners) as a
right join
(select a.petID,a.`name`,OwnerID from
(select petID,`name` from Pets) as a
left JOIN
(select petID,OwnerID from PetsOwners) as b
on a.petID = b.petID) as b
on a.ownerID = b.OwnerID
I see your question and this is easy you see the query I wrote blow:
SELECT links.`link`,
links.`link_id`
FROM links
WHERE links.`link_id` NOT IN
(SELECT Y.`link_id`
FROM users X
INNER JOIN user_visited Y ON X.`user_id` = Y.`user_id`
WHERE X.`user_id` = 22 );

SQL nested count query

I have these tables:
Discussion
----------
DiscussionID (Primary Key)
Name
....
UserDiscussion
--------------
UserID (Primary Key)
DiscussionID (Primary Key)
Participated (Boolean)
Bookmarked (Boolean)
and I need to query 2 things:
All discussions where a certain user has participated
For every participated discussion I need the total count of users who bookmarked the discussion
Here is my current query:
SELECT d.DiscussionID, d.Name
FROM Discussion d LEFT JOIN
UserDiscussion ud ON ud.DiscussionID = d.DiscussionID
WHERE ud.UserID = 1 AND ud.Participated = true;
Sample data:
Discussion:
DiscussionID | Name |
---------------------
1 First
UserDiscussion:
UserID | DiscussionID | Participated | Bookmarked |
===================================================
1 1 1 1
4 1 1 0
Output should look like this:
Discussions: [
{
DiscussionID: 1,
Name: "First",
BookmarkCount: 1
}
]
SELECT
d.DiscussionID
,d.Name
,Participated = SUM(CASE WHEN CAST(ISNULL(b.Participated,0) = 1 THEN 1 ELSE 0 END)
,Bookmarked = SUM(CASE WHEN CAST(ISNULL(b.Bookmarked,0) = 1 THEN 1 ELSE 0 END)
FROM
Discussion d
INNER JOIN UserDiscussion ud
ON d.DiscussionID = ud.DiscussionID
AND ud.Participated = true;
LEFT JOIN UserDiscussion b
ON d.DiscussionId = b.DiscussionId
GROUP BY
d.DiscussionID
,d.Name
You could use a temp table to get a count of the bookmarks related to each discussion ID
select DiscussionID, count(Bookmarked) as 'Bookmarked'
into #Bookmarks
from UserDiscussion
group by DiscussionID
then, join it to the final table on DiscussionID and you can use the count as a column.
SELECT d.DiscussionID, d.Name, b.Bookmarked
FROM Discussion d LEFT JOIN
UserDiscussion ud ON ud.DiscussionID = d.DiscussionID
left join #Bookmarked b on ud.DiscussionID = b.DiscussionID
WHERE ud.UserID = 1 AND ud.Participated = true;
You can use a in clause with a subqyery ,, and count
SELECT a.DiscussionID, a.Name, b.count(*)
FROM discussion a
INNER JOIN UserDiscussion b
WHERE a.DiscussionID in (
SELECT d.DiscussionID
FROM Discussion d
INNER JOIN UserDiscussion ud ON ud.DiscussionID = d.DiscussionID
WHERE ud.UserID = 1 AND ud.Participated = true
)
AND b.Bookmarked = true;
group by a.DiscussionID, a.Name
One way is to write a view for number of times bookmarked
CREATE OR REPLACE VIEW v_times_bookmarked (
discussion_id,
times_bookmarked ) AS
SELECT discussion_id, count(*)
FROM userdiscussion
WHERE Bookmarked = true
GROUP BY discussion_id
Then in your main query, left join to the view.
sound like you have the 1st query the 2d should be like
SELECT DiscussionID, count(UserID)
FROM UserDiscussion
WHERE DiscussionID in (SELECT DiscussionID from UserDiscussion WHERE ud.UserID = 1 AND ud.Participated = true)
AND Bookmarked = true
GROUP BY DiscussionID;
then eventually you need to join them
With the posted correction:
SELECT d.DiscussionID, d.Name, BookmarkCount
FROM Discussion d
JOIN UserDiscussion ud ON ud.DiscussionID = d.DiscussionID
JOIN (
SELECT DiscussionID as DID, count(UserID) as BookmarkCount
FROM UserDiscussion
WHERE DiscussionID in (SELECT DiscussionID from UserDiscussion WHERE
ud.UserID = 1 AND ud.Participated = true)
AND Bookmarked = true
GROUP BY DiscussionID
) ON d.DiscussionID=DID;

MYSQL - Union SELECT & GROUP BY Not working

I have 3 table, log, member, also guest, but my log i stored as customer(user)'s id only, which is either their guest_id or member_id. So here's the problem, because they're from different table, I'm not sure how to join & group together their data.
checkout_log table
id user_id checkout_as
--------------------------------------
1 1 member
2 2 guest
members table
id fullname
--------------------------------------
1 member01
2 member02
guests table
id fullname
--------------------------------------
1 guest01
2 guest02
What I wanted to Achieve - Result
id user_id fullname checkout_as
----------------------------------------------
1 1 member01 member
2 2 guest02 guest
Had tried following sql statement with UNION ALL, or GROUP BY , but had no luck.
SELECT * FROM
(
SELECT checkout_log.id,checkout_log.user_id,guests.fullname,guests.email,checkout_log.checkout_as
FROM checkout_log
LEFT JOIN checkout_product ON checkout_product.checkout_log_id = checkout_log.id
LEFT JOIN guests ON checkout_log.user_id = guests.id
UNION ALL
SELECT checkout_log.id,checkout_log.user_id,members.fullname,members.email,checkout_log.checkout_as
FROM checkout_log
LEFT JOIN checkout_product ON checkout_product.checkout_log_id = checkout_log.id
LEFT JOIN members ON checkout_log.user_id = members.id
) derivedTable
GROUP BY id
Try doing this with joins instead of union
select cl.id, cl.user_id,
coalesce(m.fullname, g.fullname) as fullname,
cl.checkout_as
from checkout_log cl left join
members m
on cl.user_id = m.id and cl.checkout_as = 'member' left join
guests g
on cl.user_id = g.id and cl.checkout_as = 'guest';

Get conversation and last message Query

i'm tring to get the conversations with the relative last message and order them by time and if is read the message. Let's go to show the my logic.
I created 3 table: inbox_join / inbox_msg / users
On the first table "inbox join" i have the datas about who have a active discussion. In this case we have id_user - "1" and id_user_2 - "4" they have a conversation.
On the inbox_msg table I have the text message, id conversation where the message will shown and other field easy to understand.
Inbox join table
Inbox_msg table
Users table
I made a query that work fine, but the my issue is that i can't have the occured_at on the inbox_msg table. I would like find a better solution for have my desidered result and i can't order how i'm looking for.
This is my query
SELECT DISTINCT (
inbox_join.id_conversation
), user_chat.name AS name_conv, user_chat.surname AS surname_conv, user_chat.username as username_conv, user_chat.id as id_chat, image_upload.name_image, (
SELECT DISTINCT (
message
)
FROM inbox_msg
WHERE inbox_join.id_conversation = inbox_msg.id_conversation
ORDER BY occured_at DESC
LIMIT 1
) AS last_msg, users.name, users.surname
FROM inbox_join
INNER JOIN users ON users.id = inbox_join.id_user
INNER JOIN users AS user_chat ON user_chat.id <> 1 AND (inbox_join.id_user_2 = user_chat.id || inbox_join.id_user = user_chat.id)
INNER JOIN image_upload ON image_upload.id_image = user_chat.profile_image
WHERE inbox_join.id_user = 1
OR inbox_join.id_user_2 = 1
Result desidered selecting the conversation about user 1:
id_conversation | id_user | name | surname | username | last_msg | occured_at_last_msg | read_msg |
1 4 E S E Yes 1380724676 0
4 5 G E K Good 1380724675 0
Query:
SELECT im.id_conversation,
im.id_user,
u.name,
u.surname,
u.username,
im.message AS last_msg,
im.occured_at AS occured_at_last_msg,
im.read_msg
FROM inbox_msg im
JOIN users u
ON u.id_user = im.id_user
JOIN (SELECT id_conversation,
MAX(occured_at) AS occured_at
FROM inbox_msg
GROUP BY id_conversation) im2
ON im2.id_conversation = im.id_conversation
AND im2.occured_at = im.occured_at
ORDER BY im.occured_at DESC
I made this query and should work fine, I would like receive comment about this query.
SELECT DISTINCT (
im.id_conversation
), users.name, users.surname, users.username, image_upload.name_image, im.message as last_msg, im.occured_at, im.read_msg
FROM inbox_join
INNER JOIN (
SELECT sub . *
FROM (
SELECT DISTINCT (
id_conversation
), id_user, message, occured_at, read_msg
FROM inbox_msg
WHERE id_user <> 1
ORDER BY occured_at DESC
) AS sub
GROUP BY sub.id_user
ORDER BY sub.occured_at DESC
) AS im ON im.id_conversation = im.id_conversation
INNER JOIN users ON im.id_user = users.id
INNER JOIN image_upload ON users.profile_image = image_upload.id_image
WHERE inbox_join.id_user = 1 || inbox_join.id_user_2 = 1

How can I select the users which are belonging to group A?

How can I select the users which are belonging to group A?
My tables are below.
my user table.
ID | name |sex
1 | bob |1
2 | kayo |2
3 | ken |1
my fos_group table
ID | name
1 | student
2 | teacher
my fos_user_user_group
user_id | group_id
1 | 1
2 | 2
3 | 1
Bob and Ken are belonging to group_1(student)
Kayo is belonging to group_2(teacher)
ex) I can select 'Bob' from user table like this
$query = $em->createQuery(
"SELECT p.name,p.sex
FROM UserBundle:User p WHERE
p.id = '1' );
But I would like to select the users which belongs to student group(Bob and Ken)
How should I change the sentence in createQuery?
I just guess I need to join the tables though...
additional....
I have tried like this accroding to Fabio's answer
$query = $em->createQuery(
"SELECT p,p.id,p.username,p.userKey
FROM UserBundle:User p
INNER JOIN fos_user_user_group b
ON a.ID = b.user_id
INNER JOIN fos_group c
ON b.group_id = c.ID
WHERE c.group_id = '1'");
$this->data["teachers"] = $query->getResult();
but it says
[Semantical Error] line 0, col 94 near 'fos_user_user_group': Error: Class 'fos_user_user_group' is not defined.
I guess it means I dont have entity for 'fos_user_user_group'.
I have only entity class for Group and User,other tables were created automatically.
In meanwhile,I used like this in other place in $formmapper.
->add('teacher',
null,
array(
'query_builder' =>
function (\Doctrine\ORM\EntityRepository $rep) {
return $rep->
createQueryBuilder('s')
->join('s.groups', 'g')
->where('g.name = :group')->setParameter('group','TeacherGroup');
})
)
it works well,
how can I change this sentence for createQuery()?
I think you can use a INNER JOIN query
SELECT p.name,p.sex
FROM User p
INNER JOIN fos_user_user_group b
ON a.ID = b.user_id
INNER JOIN fos_group c
ON b.group_id = c.ID
WHERE c.group_id = '1'