SQL extract unique data from two columns in same table - sql

I have a table friends, which contains the following columns:
friend_id and friend_of (both are storing unique user ids)
lets say the table friends contains the following data:
friend_id | friend_of
-------------------------
123 | 456
456 | 789
456 | 123
So this means that:
user with id=123 have one friend with id=456
user with id=456 have two friends with ids=123 (friend_1) & 789(friend_2)
user with id=789 have one friwnd with id=456
I want to write a query that given a single user id shows every friend that this user has (with their ids).
For example:
if given user with id=123 the output would be users with ids=456
if given user with id=789 the output would be users with ids=456
if given user with id=456 the output would be users with ids=123 and 789
Can you help me with the query I need?

(select friend_id as all_friends from friends where friend_of=ID)
uninon
(select friend_of as all_friends from friends where friend_id=ID)
I suppose you are interested in the case where an id exists only in one of the columns. Above query would address this. Note that union is used here and not union all as unique values are required.

select friend_id, friend_of
where friend_id = '456'
just change ID to get desire ouput

Just use union
Declare #id int = 1;
select f.friendof from
#YourTableName as f where f.friendId = #id
union
select f.friendId from
#YourTableName as f where f.friendof = #id

You can use the query SELECT * FROM friends WHERE friend_id='456', which should get all of the friends of 456. Then do a join on your "users" table using the foreign key friend_of.
EDIT: I didn't realize friends was a two-way relationship. In that case, use a UNION first, some of the other responses talk about it. :)

Related

Update user id by looking up two other tables

I have a table/sql issue I don't know how to solve.
I need to update/create a table of user ids with order ids.
Therefore I have to get a new user_id, by searching for the email in an old list.
With the email adress I need to look up the new user id.
So the logic is like:
order_id -> look at the old user_id -> look at the email -> look at the new user_id
I tried to create an example:
---------------------
TABLE: USERS_OLD (a list of user ids and an email adress)
id email
1 test1#email.com
2 test2#email.com
3 test3#email.com
4 test4#email.com
---------------------
---------------------
TABLE: USER_ORDERS_OLD (the connection of an order id with a user id)
user_id order_id
1 DLEFGM
2 OPDFGT
3 UZDFGP
4 POIDSX
---------------------
---------------------
TABLE: USERS_NEW (a new list of users id with the same emails from table USERS_OLD)
id email
5 test1#email.com
9 test2#email.com
10 test3#email.com
17 test4#email.com
---------------------
What I want to create:
---------------------
TABLE: USER_ORDERS_NEW
user_id order_id
5 DLEFGM
9 OPDFGT
10 UZDFGP
17 POIDSX
---------------------
I have no idea how to do that action. I don't even know what to search for.
What I managed to do is a LEFT JOIN sql statement to compare the user ids and create a list of matching user_ids.
But I have no idea how to look up over even more tables...
Hopefully someone can help me.
If it's easier I could also try to do it in spreadsheets.
Thanks in advance!
Assuming you just want to return the query then use;
SELECT u3.id, u2.order_id
FROM USERS_OLD u1
JOIN USER_ORDERS_OLD u2 ON u1.id = u2.user_id
JOIN USERS_NEW u3 ON u1.email = u3.email;
However, if you want to write the result into a new table, then you need to create the table first.
CREATE TABLE USER_ORDERS_NEW (user_id INTEGER, order_id VARCHAR(50));
INSERT INTO USER_ORDERS_NEW (user_id, order_id)
SELECT u3.id, u2.order_id
FROM USERS_OLD u1
JOIN USER_ORDERS_OLD u2 ON u1.id = u2.user_id
JOIN USERS_NEW u3 ON u1.email = u3.email;
See Demo
With your example you should be able to accomplish this with this query
INSERT INTO user_orders_new (user_id, order_id) SELECT usr_new.id, ord_old.order_id
FROM users_old usr_old JOIN users_new usr_new ON usr_new.email = usr_old.email
JOIN user_orders_old ord_old ON ord_old.user_id = usr_old.id;
You may want to opt for a LEFT JOIN on the old order table if you intend to migrate the ids regardless of whether they have had an order or not although I assume that's not the intention to populate the new order table with new users ids that haven't made an order.

Search single entity which is presented by multiple rows SQL

I have User table which contains same user represented by different entities all around. For example
User Table
==========================
id name
1 John Doe
2 Doe, John
3 Nicholas Cage
4 BlackRiderXXX
5 Nicholas cage
where users John Doe, Doe, John, BlackRiderXXX are the same people. Also, Nicholas Cage and Nicholas cage are the same people. Other tables refer to user.id randomly based on which user object did the action.
For Action table it'll look like
Action Table
==========================
id user_id some_other_stuff
1 1 ...
2 2 ...
3 1 ...
4 4 ...
5 3 ...
Where the actions 1,2,3,4 are all done by John Doe.
I'll have these users merged by the user manually meaning we'd know who is whom. They'd also select which User is the one they'd like to be as their main user account so we need to know this information as well.
I'm simplifiying a bit but I have a dozen tables which are like the Action table I provided above. We have mainly two use cases on how we will need to query:
1) Find actions which are done by user X (which should check all the users entities belonging to user X)
2) Find actions and group unique users
Main point is we will be using it everywhere around the codebase on 100+ queries so we want to design it well. How can I construct a system where the query will be simple enough also powerful enough to handle different querying ways?
Thanks
PS: We are using PostgreSQL
Why not include the "main" user in the first table?
User Table
id name main_user_id
1 John Doe 1
2 Doe, John 1
3 Nicholas Cage 2
4 BlackRiderXXX 1
5 Nicholas cage 2
Then you would join on:
select . . .
from actions a join
users u
on a.user_id = u.id
where u.main_user_id = 1;
If you want this selectable per end user, then use a different table:
create table end_user_users (
end_user_users_id serial primary key,
end_user_id int references end_users (end_user_id),
end_user_user_id int references users (id),
end_user_main_user_id int references users (id)
);
Then the query would look like:
select . . .
from actions a join
end_users_users euu
on euu.end_user_user_id = a.user_id and
euu.end_user_id = $my_id
where euu.end_user_main_user_id = 1;
You can use regexp_replace(),initcap() and trim() functions to refine and extract the common name strings to be grouped, and then generate values for newly created action_id column depending on them :
with new_action0 as
(
select u.id as id,
case when strpos(u.name,',') > 0 then
initcap(trim(regexp_replace(trim(u.name),'(.*),(.*)','\2 \1')))
else
case when lower(trim(u.name))='blackriderxxx' then
'John Doe'
else
trim(initcap(u.name))
end
end as name
from action u
)
select n.id, dense_rank() over (order by n.name) as user_id
from new_action0 n;
Demo
A new decent user table can be created by using this query with create table .. as statement

Create view from table with multiple primary key

I've a table like this one:
Column | Type | Modifiers
username | character varying(12) | not null
electioncode | integer | not null
votes | integer | default 0
PRIMARY KEY (username, electioncode)
i need to create a view with username, electioncode, max(votes)
if i use this query it works fine but without username:
SELECT electioncode, max(votes) from table group by electioncode;
if i add username it asks me to add it into the group by but if i do that it gives me the entire table instead of just the username-electioncode-maxvotes
Do you want to get username associated with this number of votes? Or any username in given election code?
If the first:
SELECT
DISTINCT ON ( electioncode )
*
FROM table
ORDER BY electioncode, votes desc;
if the other:
SELECT
electioncode,
min(username),
max(votes)
FROM
table
GROUP BY electioncode;
Your username field seems to be unique. Every record has different username (I am assuming) thus when you group by username it will give you all the records. What you are trying to do has a logic issue not syntax issue.
A suggestion: You want to write on a piece of paper the output you would like to see and then construct the query... If you want Username, Electioncode and max (votes) then imagine how you would display the data where two usernames - user1 and user 2 who have electioncode 001 and voted 1 each? How would you display this?

Select all items in a table that do not appear in a foreign key of another table

Take for example an application which has users, each of which can be in exactly one group. If we want to SELECT the list of groups which have no members, what would be the correct SQL? I keep feeling like I'm just about to grasp the query, and then it disappears again.
Bonus points - given the alternative senario, where it's a many to many pairing, what is the SQL to identify unused groups?
(if you want concrete field names:)
One-To-Many:
Table 'users': | user_id | group_id |
Table 'groups': | group_id |
Many-To-Many:
Table 'users': | user_id |
Table 'groups': | group_id |
Table 'user-group': | user_id | group_id |
Groups that have no members (for the many-many pairing):
SELECT *
FROM groups g
WHERE NOT EXISTS
(
SELECT 1
FROM users_groups ug
WHERE g.groupid = ug.groupid
);
This Sql will also work in your "first" example as you can substitute "users" for "users_groups" in the sub-query =)
As far as performance is concerned, I know that this query can be quite performant on Sql Server, but I'm not so sure how well MySql likes it..
For the first one, try this:
SELECT * FROM groups
LEFT JOIN users ON (groups.group_id=users.group_id)
WHERE users.user_id IS NULL;
For the second one, try this:
SELECT * FROM groups
LEFT JOIN user-group ON (groups.group_id=user-group.group_id)
WHERE user-group.user_id IS NULL;
SELECT *
FROM groups
WHERE groups.id NOT IN (
SELECT user.group_id
FROM user
)
It will return all group id which not present in user

SQL Select based on Link Field

I feel like an idiot asking this...
Table 1: users
id serial
person integer
username char(32)
Table 2:persons
id serial
name char(16)
Can I run a query that returns the name field in persons by providing the username in users?
users
1 | 1 | larry123
persons
1 | larry
2 | curly
SQL?
select name from persons where users.person=persons.id and users.username='larry123';
with the desired return of
larry
I have been doing it with two passes until now and think maybe a nested select using a join is what I need
1 | larry
It sounds like you're asking how to do a join in SQL:
SELECT
name
FROM
users JOIN persons ON (users.person = persons.id)
WHERE
users.username = 'larry123';
that is almost the query you wrote. All you were missing was the join clause. You could also do that join like this:
SELECT name
FROM users, persons
WHERE
users.person = persons.id
AND users.username = 'larry123';
I suggest finding a well-written introduction to SQL.