Compound SQL SELECT - sql

I have the following two tables:
auth_user
id
username
is_active (boolean)
...
useprofile_userprofile
id
user_id
...
How would I find all auth_user objects where is_active=0 and there is no userprofile_userprofile object with that user_id? For example, an entry like this --
auth_user
id = 1
username = hello#gmail.com
is_active = 0
and userprofile_userprofile has no object where user_id = 1

SELECT *
FROM auth_user A
LEFT JOIN userprofile_userprofile B ON A.id=B.user_id
WHERE A.is_active = false and B.user_id IS NULL
when B.user_id is NULL that means it cannot find a row where user_id=1.
This assumes that the id in table userprofile_userprofile are all not NULL.

SELECT
*
FROM
auth_user
WHERE
auth_user.is_active=0
AND NOT EXISTS
(
SELECT
NULL
FROM
userprofile_userprofile
WHERE
userprofile_userprofile.user_id=auth_user.id
)

select * from auth_user au
where au.is_active = 0 and
not exists(select * from userprofile_userprofile uu where uu.user_id = au.user_id)

Apart from the other solutions you can also do it via LEFT JOIN
SELECT
*
FROM
auth_user au
LEFT JOIN useprofile_userprofile uu ON au.id = uu.user_id
WHERE uu.id IS NULL
AND au.is_active = 0

You are looking for Table Joins. Reference this tutorial:
http://www.tizag.com/mysqlTutorial/mysqljoins.php
To answer your question, you are looking for something along the lines of:
"SELECT auth_user.username,auth_user.is_active,useprofile_userprofile.user_id WHERE is_active = 0 AND user_id != 1"

select au.id,au.username,count(up.id) from auth_user au
left outer join useprofile_userprofile up
on au.id=up.user_id
where is_active = 1
group by au.id,au.username
having count(up.id)=0

Related

Return Duplicate emails along with User Ids that are different

I'm running into an issue with a duplicate query and I hope you guys can help.
Essentially what I want to do is find and list of the duplicate emails associated with different userids
My query is:
select UserId, acitveid, email, userstatusid
from (select u.UserId, u.acitveid, cd.email, u.userstatusid,
count(*)over (partition by cd.email) as cnt
from ContactDetails cd
join UserContactDetails ucd on ucd.ContactDetailsId = cd.ContactDetailsId
join dbo.[User] u on u.UserId = ucd.UserId ) ua
where cnt >1
The issue I have with the above query is that it is returning the same userids for some of the results so it looks like:
Userid AcitveId email UserStatusid
123 1 abc#123.com 1
123 1 abc#123.com 1
135 1 efg#123.com 1
142 1 efg#123.com 1
The results Im looking for are simply:
Userid AcitveId email UserStatusid
135 1 efg#123.com 1
142 1 efg#123.com 1
WITH base AS (
SELECT DISTINCT u.UserId
,u.acitveid
,cd.email
,u.userstatusid
,
FROM ContactDetails cd
JOIN UserContactDetails ucd ON ucd.ContactDetailsId = cd.ContactDetailsId
JOIN dbo.[User] u ON u.UserId = ucd.UserId
)
,duplicate_emails AS (
SELECT email
,count(userId) AS cnt
FROM base
GROUP BY 1
HAVING count(userId) > 1
)
SELECT b.*
FROM base b
JOIN duplicate_emails de ON b.email = de.email
A self join across Email = email and id <> id would work fine here. That said, your request and lack of sample data means that we are largely guessing based off the query and sample output you have provided. The below should get you pretty close and, if you update your OP, I am sure we can get you exactly what you're after.
SELECT ActiveUser.UserID Active_UserID,
ActiveUser.ActiveID Active_ActiveID,
ContactDetails.email AS Email,
DuplicateUser.UserID AS Dup_UserID,
DuplicateUser.ActiveID As Dup_ActiveID
FROM ContactDetails INNER JOIN
ContactDetails AS Duplicate ON ContactDetails.email = Duplicate.email AND ContactDetails.UserID <> Duplicate.UserID INNER JOIN
UserContactDetails AS ActiveUserContactDetails ON ActiveUserContactDetails.ContactDetailsID = ContactDetails.ContactDetailsID INNER JOIN
dbo.[User] AS ActiveUser ON ActiveUser.UserID = ActiveUserContactDetails.UserID INNER JOIN
UserContactDetails AS DuplicateUserContactDetails ON DuplicateUserContactDetails.ContactDetailsID = Duplicate.ContactDetailsID INNER JOIN
dbo.[User] AS DuplicateUser ON DuplicateUser.UserID = UserContactDetails.UserID

SQL SELECT composite primary key

I have 2 tables User1 and Relationship and it's some kind of user-friends relationship. I need to find all the friends of a user.
For example: I have a user with ID=3 and I need to find all the users who have Relationship.STATUS = 1 with this user.
FYI, I'm a beginner in SQL, so I know it's quite simple task but I can't handle it.
I’ve tried to use JOIN but it wasn't successfully.
SELECT *
FROM USER1
RIGHT JOIN RELATIONSHIP R on USER1.USER1_ID = R.USER_ID_FROM OR USER1.USER1_ID = R.USER_ID_TO
WHERE R.USER_ID_FROM = :id
OR R.USER_ID_TO = :id AND R.STATUS = :status AND USER1_ID != :id;
My tables:
TABLE USER1
(
USER1_ID NUMBER PRIMARY KEY,
USER_NAME NVARCHAR2(64),
REAL_NAME NVARCHAR2(64),
EMAIL NVARCHAR2(64),
PHONE_NUMBER NVARCHAR2(64),
BIRTH_DATE TIMESTAMP,
POST_ID NUMBER,
PASSWORD NVARCHAR2(16)
);
TABLE RELATIONSHIP
(
USER_ID_FROM NUMBER NOT NULL,
USER_ID_TO NUMBER NOT NULL,
STATUS SMALLINT DEFAULT 0,
CONSTRAINT FK_USER_ONE FOREIGN KEY (USER_ID_FROM) REFERENCES USER1 (USER1_ID),
CONSTRAINT FK_USER_TWO FOREIGN KEY (USER_ID_TO) REFERENCES USER1 (USER1_ID),
CONSTRAINT PK_RELATIONSHIP PRIMARY KEY (USER_ID_FROM, USER_ID_TO)
);
If you just want the ids then you can use conditional logic to which which of the user ids you want:
select (case when user_id_from = 1 then user_id_to else user_id_from
end) as other_user_id
from relationship r
where 1 in (user_id_from, user_id_to) and
status = 3;
If you actually want all the user information, I would suggests exists:
select u.*
from user1 u
where exists (select 1
from relationship r
where r.status = 3 and
( (r.user_id_from = 1 and r.user_id_to = u.id) or
(r.user_id_to = 1 and r.user_id_from = u.id)
)
);
Hum not sure but I would try something like this:
SELECT u.* FROM USER1 u LEFT JOIN RELATIONSHIP r ON r.USER_ID_FROM = :id AND r.STATUS = 1 AND u.USER1_ID = r.USER_ID_TO;
Where the id is the ID of the user you want to find the friends.
SELECT *
FROM USER1 U
LEFT JOIN RELATIONSHIP R ON R.USER_ID_FROM = U.ID AND R.[STATUS] = 1
LEFT JOIN USER1 F ON R.[USER_ID_TO] = F.[ID]
WHERE U.[Id] = your_id
Then simply filter the users. Left join is used because a user may not have any friends. And I understood that you want to find the user and any friends for that users.
Try this:
(SELECT *
FROM USER1 u
LEFT JOIN RELATIONSHIP f ON u.USER1_ID = f.USER_ID_FROM
WHERE f.USER_ID_TO= 3 AND f.STATUS = 1)
union
(SELECT *
FROM USER1 o
LEFT JOIN RELATIONSHIP t ON o.USER1_ID = t.USER_ID_TO
WHERE t.USER_ID_FROM= 3 AND t.STATUS = 1)

SQL - Updating rows in table based on multiple conditions

I'm kinda newbie in SQL and I have to create a request to update multiple rows in table based on multiple conditions.
From this example:
id email organisationid principaluserid role
1 john#smith.com MULT null 100
2 john#smith.C-100.com C-100 1 25
3 john#doe.com MULT null 100
4 john#doe.C-101.com C-101 3 50
5 john#doe.C-102.com C-102 3 25
6 jessica#smith.com C-102 null 25
The goal is to update all the entries from the User table where organisationid equals 'MULT' and who have only 1 principaleuserid match.
From the example above, the first 2 entries match my conditions.
I need then to replace the id=2 email (john#smith.C-100.com) with the one from id=1 email (john#smith.com).
To do the job step by step, I tried to retrieve all the entries that match my condition with this request:
Edit from #The_impaler answer:
SELECT * FROM User a1 WHERE a1.organisationid = 'MULT' AND (
SELECT COUNT(*) FROM User a2 WHERE a2.principaluserid = a1.id
) = 1;
But i'm still bugging on the way to update the entries. Any help is appreciated!
If I understand correctly, an update should do the trick:
update user u
set u.email = um.email
from user um
where um.id = u.principaluserid and
um.organizationid = 'MULT' and
not exists (select 1
from user up2
where up2.principaluserid = u.principaluserid and
up2.id <> u.id
);
Based on #The_impaler advice, I did this query that seems to answer my need:
UPDATE user u1
SET organisationid = (SELECT u2.organisationid FROM user u2 WHERE u1.id = u2.principaluserid),
WHERE u1.organisationid = 'MULT' AND
(SELECT COUNT(*) FROM user u2 WHERE u2.principaluserid = u1.id) = 1;
You could use an update based on join
UPDATE user u1
SET u1.email = u2.email
FROM user u2
WHERE u2.organisationid = 'MULT'
AND u1.id = u2.principaluserid
and if you need only the value that have only a single principaluserid
the you could use
UPDATE user u1
SET u1.email = u2.email
FROM user u2
INNER JOIN
(
select principaluserid , count(*)
from user
group by principaluserid
having count(*) =1
) t2 ON t2.principaluserid = u2.principaluserid
AND u2.organisationid = 'MULT'
AND u1.id = u2.principaluserid

postgresql/sql - Improve query where same sub select used for IN & NOT IN select

How could I improve this query. The problem is that the same sub select is used twice, first for an IN and then for a NOT IN:
SELECT
"activities".*
FROM "activities"
WHERE (
user_id IN (
SELECT followed_id
FROM relationships
WHERE follower_id = 1 AND blocked = false)
AND
targeted_user_id NOT IN (
SELECT followed_id
FROM relationships
WHERE follower_id = 1 AND blocked = false )
)
Using a common table expression will help:
WITH users_cte AS (
SELECT followed_id
FROM relationships
WHERE follower_id = 1 AND blocked = false)
SELECT "activities.*"
FROM "activities"
WHERE user_id IN (SELECT followed_id FROM users_cte)
AND targeted_user_id NOT IN (SELECT followed_id FROM users_cte)
I would phrase the query using exists:
SELECT a.*
FROM activities a
WHERE EXISTS (SELECT 1
FROM relationships r
WHERE r.followed_id = a.user_id AND
r.follower_id = 1 and
r.blocked = false
) AND
NOT EXISTS (SELECT 1
FROM relationships r
WHERE r.followed_id = a.targeted_user_id AND
r.follower_id = 1 and
r.blocked = false
);
Then, I would create an index on relationships(followed_id, follower_id, blocked):
create index idx_relationships_3 on relationships(followed_id, follower_id, blocked);
From a performance perspective, the index should be much better than using a CTE (if you are really using Postgres, MySQL doesn't support CTEs).
In addition to indexes you could try rewriting the query as follows:
SELECT distinct a.*
FROM activities a
join relationships x
on a.user_id = x.followed_id
left join relationships r
on a.targeted_user_id = r. followed_id
and r.follower_id = 1
and r.blocked = false
where r.followed_id is null
and x.follower_id = 1
and x.blocked = false
If the inner join to relationships (x) above does not result in repeated rows of activities, you can get rid of the DISTINCT.

Using a join query to retrieve absent data from second table

Let's consider these two tables:
TABLE(T_USER)
user_id
TABLE(T_MESSAGE)
msg_type (values = 0, 1, 2, 3)
answered (values = 0, 1)
user_id
As you can see, there can be 0 - n message for any user.
I am trying to retrieve, using a SQL query (on Oracle 10g), the list of all users for which no message of a certain type and not answered exists (i.e. where msgType = 1 and answered = 0 for example). This user could have others messages, if none of them fulfill these criteria, then my request should
What should this query look like?
SELECT *
FROM T_USER u
WHERE NOT EXISTS (SELECT NULL
FROM T_MESSAGE
WHERE user_id = u.user_id
AND msgType = 1
AND answered = 0)
Also want to notice that solution with NOT EXISTS will be more performant in oracle than NOT IN and LEFT JOIN.
select u.user_id
from T_USER u
left join T_MESSAGE m
on u.user_id = m.user_id
and m.msgType = 1
and m.answered = 0
where m.user_id is null
SELECT user_id FROM t_user t where not exists ( select 1 from t_message where user_id = t.user_id and ... )
How about
SELECT * FROM T_USER WHERE user_id NOT IN
(SELECT user_id FROM T_MESSAGE WHERE msgType = 1 AND answered = 0)