SQL SELECT composite primary key - sql

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)

Related

What's the best way to compare the results of 2 Subselects on the same table?

Is there a better way to compare the result of 2 Sub-Selects on the same Table, than using 2 separate Queries?
In the following Query, I'd like to select all incidents where the "client" of the "creator" is not equal to the "client" of another user which I pass later on.
SELECT
*
FROM
incident i
WHERE
i.client_id = 150
AND ( --can this AND be shortend?
SELECT
ur1.CLIENT_ID
FROM
USER ur1
WHERE
ur1.USER = upper(i.CREATOR)
) != (
SELECT
ur2.CLIENT_ID
FROM
USER ur2
WHERE
ur2.USER = upper('other')
)
Minimal reproducable example
Users inside the USER-Table are always Uppercase
Every User is unique
1 User can only have 1 Client_Id
https://dbfiddle.uk/?rdbms=oracle_18&fiddle=99ac066a9abd339cd9a80a5b78716138
If you have the constraints:
ALTER TABLE "USER" ADD CONSTRAINT
user__id_user__pk PRIMARY KEY ("USER");
ALTER TABLE "USER" ADD CONSTRAINT
user__id_user__u UNIQUE (client_id, "USER");
ALTER TABLE incident ADD CONSTRAINT
incident__id_creator__fk FOREIGN KEY (client_id, creator)
REFERENCES "USER" (client_id, "USER");
Then you can use:
SELECT *
FROM incident i
WHERE i.client_id = 150
AND NOT EXISTS (
SELECT u.client_id
FROM "USER" u
WHERE u."USER" = upper('joe')
AND u.client_id = i.client_id
)
If you do not have the foreign key constraint (and just have the unique/PK constraints on the USER table) then:
SELECT *
FROM incident i
WHERE i.client_id = 150
AND EXISTS (
SELECT 1
FROM "USER" u
WHERE u."USER" IN (i.creator, upper('joe'))
HAVING COUNT(DISTINCT client_id) > 1
)
db<>fiddle here
Maybe self join? Something like this:
SELECT i.*
FROM incident i
JOIN USER u1 ON u1.USER = i.creator
JOIN USER u2 ON u2.client_id <> u1.client_id
WHERE i.client_id = 150
AND u2.USER = 'OTHER'
I think you can do it this way,
SELECT i.*
FROM incident i, user ur1, user ur2
WHERE i.client_id = 150
AND ur1.user = UPPER(i.creator)
AND ur2.user = UPPER(‘other’)
AND ur1.client_id != ur2.client_id

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

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

Using Outer Apply To return null values

I have the following tables:
User which has a primary key and Username e.g.
ID Username
1 Fred
2 John
3 Jack
Event which has primary key and event name
ID Eventname
1 Ferrari Road Show
2 Flower Show
UserStatusUpdates table which has primary key, a status update and a userid (foreign key)
ID UserID UserStatus
1 1 Really Good
2 1 Leaving Now
3 2 I concur
And An Event Attendee table which has a primary key and two foreign keys (Event primary key and User primary key)
ID UserID EventID
1 1 1
2 2 1
3 3 1
The problem I am encountering is that I need to return all the event attendees plus their latest status update, however there are cases where the user has not actually made a status update.
This is what my query looks like:
SELECT EventAttendee.*, Users.UserName,Users.USERS_ID,
Users.ThumbnailPic,
Users.CountryName,
ISNULL(UserStatusUpdates.UserStatus,'No Updates')AS LastUpdate,
UserStatusUpdates.MediaTypeID,UserStatusUpdates.USERSTATUS_ID,(UserStatusUpdates.AddDate)
FROM EventAttendee
JOIN Users ON Events.UserID = Users.USERS_ID
OUTER APPLY (SELECT TOP 1 UserStatusUpdates.UserStatus,UserStatusUpdates.MediaTypeID,
UserStatusUpdates.USERSTATUS_ID,UserStatusUpdates.AddDate, UserStatusUpdates.UserID
FROM UserStatusUpdates where UserStatusUpdates.UserID = Users.USERS_ID
ORDER BY AddDate DESC) AS UserStatusUpdates WHERE UserStatusUpdates.UserID = EventAttendee.UserID
WHERE EventAttendee.EventID = #EventID
AND Users.bDeleted = 'False'
AND Users.bSuspended = 'False'
END
How can I get back users who may not have made an update?
Your query has multiple where clauses, and you're already specifying the UserStatusUpdates.UserID = Users.USERS_ID join in the subquery. Try this:
SELECT
EventAttendee.*,
Users.UserName,Users.USERS_ID,
Users.ThumbnailPic,
Users.CountryName,
ISNULL(UserStatusUpdates.UserStatus,'No Updates') AS LastUpdate,
UserStatusUpdates.MediaTypeID,
UserStatusUpdates.USERSTATUS_ID,
UserStatusUpdates.AddDate
FROM
EventAttendee
JOIN Users ON
Events.UserID = Users.USERS_ID
OUTER APPLY (
SELECT TOP 1
UserStatusUpdates.UserStatus,
UserStatusUpdates.MediaTypeID,
UserStatusUpdates.USERSTATUS_ID,
UserStatusUpdates.AddDate,
UserStatusUpdates.UserID
FROM
UserStatusUpdates
WHERE
UserStatusUpdates.UserID = Users.USERS_ID
ORDER BY
AddDate DESC
) AS UserStatusUpdates
WHERE
EventAttendee.EventID = #EventID
AND Users.bDeleted = 'False'
AND Users.bSuspended = 'False'
END

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)