Using a join query to retrieve absent data from second table - sql

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)

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

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.

SQL query to check if user assigned with a specific value and does not a different value assigned to the same user?

We can have users with multiple valueIDs. In SQL Server I am trying to pull all users that have valueID of 3 but do not have valueID of 1 and 2. So Table A would have a user column and a valueID column.
How do I write a SQL query to do this?
Also, any good resources to get my SQL query skills up to par?
Much appreciated.
Try:
SELECT user
FROM A outer
WHERE valueID = 3
AND NOT EXISTS
(
SELECT 1
FROM A inner
WHERE
(
valueID = 1
OR valueID = 2
)
AND inner.user = outer.user
)
Here's one more.... (all users with valueid = 3 and nothing else)
SELECT [USER]
FROM A
GROUP BY [USER]
HAVING MAX(CASE WHEN valueid = 3 THEN 0 when valueid IN (1,2) THEN 1 END) = 0;
This query will return all users that have values (3 and 1) or (3 and 2) or just 3
select user
from mytable t1
where valueId = 3
and (select count(distinct valueId)
from mytable t2 where t2.user = t1.user
and valueId IN (1,2)) < 2
A simple way to get what you asked if you meant users with a value of 3 except those which also have values of 1 and 2
Select s.UserID From SomeTable s
Where s.UserID NOT In
(select s1s.UserID From SomeTable s1s
inner join SomeTable s2s On s1s.UserID = s2s.UserID
Where s1s.ValueId = 1 And s2s.ValueId = 2)
Or
Select s.UserID From SomeTable s
Left Join
(select s1s.UserID From SomeTable s1s
inner join SomeTable s2s On s1s.UserID = s2s.UserID
Where s1s.ValueId = 1 And s2s.ValueId = 2) both
Where both.userID is null
I'm not really sure what your table structure is, but it's likely the below query should work depending on column names...
SELECT user, valueID
FROM users
WHERE valueID = 3

Compound SQL SELECT

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

SELECT Data from multiple tables?

I have 3 tables, with 3 fields all the same. I basically want to select information from each table
For example:
userid = 1
I want to select data from all 3 tables, where userid = 1
I am currently using:
SELECT r.*,
p.*,
l.*
FROM random r
LEFT JOIN pandom p ON r.userid = p.userid
LEFT JOIN landom l ON l.userid = r.userid
WHERE r.userid = '1'
LIMIT 0, 30
But it doesn't seem to work.
with 3 fields all the same
So you mean that you want the same 3 fields from all 3 tables?
SELECT r.col1, r.col2, r.col3
FROM random r
WHERE r.userid = '1'
LIMIT 0, 30
UNION ALL
SELECT p.pcol1, p.pcol_2, p.p3
FROM pandom p
WHERE p.userid = '1'
LIMIT 0, 30
UNION ALL
SELECT l.l1, l.l2, l.l3
FROM landom l
WHERE l.userid = '1'
LIMIT 0, 30
The fields don't have to be named the same, but the same types need to line up in position 1, 2 and 3.
The way the limits work is:
it will attempt to get 30 from random.
If it has 30 already, it won't even look at the other 2 tables
if it has less than 30 from random, it will try to fill up to 30 from pandom and only finally landom
SELECT t1.*, t2.*, t3.*
FROM `random` as t1, `pandom` as t2, `landom` as t3
WHERE t1.`userid`='1' AND t2.`userid`='1' AND t3.`userid`='1'
SELECT * FROM `random`
JOIN `pandom` USING (`userid`)
JOIN `landom` USING (`userid`)
WHERE `userid`='1'