Find Specific Rows - sql

I'm trying to build a rather specific query to find a set of user_ids based on topics they have registered to.
Unfortunately it's not possible to refactor the tables so I have to go with what I've got.
Single table with user_id and registration_id
I need to find all user_ids that have a registration_id of (4 OR 5) AND NOT 1
Each row is a single user_id/registration_id combination.
My SQL skills aren't the best, so I'm really scratching my brain. Any help would be greatly appreciated.

SELECT *
FROM (
SELECT DISTINCT user_id
FROM registrations
) ro
WHERE user_id IN
(
SELECT user_id
FROM registrations ri
WHERE ri.registration_id IN (4, 5)
)
AND user_id NOT IN
(
SELECT user_id
FROM registrations ri
WHERE ri.registration_id = 1
)
Most probably, user_id, registration_id is a PRIMARY KEY in your table. If it's not, then create a composite index on (user_id, registration_id) for this to work fast.

Possibly not the best way to do it (my SQL skills aren't the best either), but should do the job:
SELECT user_id
FROM table AS t
WHERE registration_id IN (4, 5)
AND NOT EXISTS (SELECT user_id
FROM table
WHERE user_id = t.user_id
AND registration_id = 1);

Another way with eliminating duplicates of user_id:
SELECT user_id
FROM registrations
WHERE registration_id IN (4, 5)
except
SELECT user_id
FROM registrations
WHERE registration_id =1
One use of a table:
select user_id from registrations
where registration_id <=5
group by user_id
having MIN(registration_id)>1 and MAX(registration_id)>= 4

Related

SQL SELECT statement with a many-to-many extra table

I have a table that links users. Consider the following:
**Table contracts:**
contract_id int,
contract_number varchar,
user_id int
**Table users:**
user_id int
**Table user_links**
user_id int,
linked_user_id int
The user_links table can have 0 rows for a particular user_id, given the user doesn't have linked users, so a select statement can return either a row or NULL.
The approach with
left join user_links ul on ul.user_id = contracts.user_id OR ul.linked_user_id = contracts.user_id doesn't seem to work if there is no row in the user_links table.
Given only an int user_id, how can I get rows from the contracts table for both user_id AND linked_user_id?
For example, if the user_id 1 has a linked_user_id 2, I need the rows from contracts for both users; however, if the user doesn't have a row in user_links table, I still need to get their contracts.
Assuming your input user_id is the variable #user_id, then the below query will get you all the contracts of that user, and if any linked user.
SELECT * from contracts c
where c.user_id = #user_id
OR c.user_id IN ( SELECT linked_user_id from user_links ul
WHERE ul.user_id = #user_id)

Is group by good for this use case?

I have a table that has user_id and role_id. I want to group user_id: 1 which also can multiple roles and In the end, I want to show count. Like for this user_id, there are 7 roles.
How can I achieve this in raw SQL query?
SELECT user_id, count(role_id) c
FROM atable
GROUP BY user_id
It seems that you are looking for typical group by:
select user_id,
count(role_id)
from MyTable
group by user_id;
here we group all records within MyTable by their user_id and then count all non null roled_id within each group. Depending on how role_id should be count you may want to put
count(all role_id)
to count null role_id as well as not null ones
count(distinct role_id)
to count distinct role_id in each group.

How to insert unique ID from subquery into a table?

I have two SQL Server tables: users_flags and users.
users:
user_id
email_address
1
john#company.com
2
amy#company.com
3
john#company.com
2
amy#company.com
users_flags:
flag_id
user_id
How do I insert all unique user_id values from the users table into the users_flags table, using a subquery to filter by email_address?
For example, I have a list of email addresses that I need to retrieve the user_id for:
SELECT user_id FROM users
WHERE email_address IN ('john#company.com',
'amy#company.com',
'guster#company.com')
Normally, I would just use this as a subquery of my INSERT statement (I need to hard code the flag_id):
INSERT INTO users (flag_id, user_id)
SELECT 3,
user_id
FROM users
WHERE email_address IN ('john#company.com',
'amy#company.com',
'guster#company.com')
However, since my users dataset currently has some duplicate data, I need to get only the DISTINCT user_id records from that table.
I can not use the DISTINCT keyword on user_id in my subquery, though (invalid syntax). How would I update my INSERT statement to account for only unique user IDs?
use window function row_number()
INSERT INTO users (flag_id, user_id)
SELECT *
FROM
(SELECT 3 as flag_id,
user_id,
row_number() over(partition by user_id order by (select null)) as seq
FROM users
WHERE email_address IN ('john#company.com',
'amy#company.com',
'guster#company.com')) T
WHERE seq = 1
You should be able to use select distinct:
INSERT INTO users (flag_id, user_id)
SELECT DISTINCT 3, user_id
FROM users
WHERE email_address IN ('john#company.com',
'amy#company.com',
'guster#company.com');
They're are many solution for this to avoid duplicates, for example:
NOT EXISTS
INSERT INTO users (flag_id, user_id)
SELECT u.3,
u.user_id
FROM users u
WHERE NOT EXISTS(SELECT user_id
FROM users u2
WHERE u2.user_id = u.user_id)
;with Temp as(
SELECT Distinct user_id FROM users
WHERE email_address IN ('john#company.com',
'amy#company.com',
'guster#company.com')
)
INSERT INTO users (flag_id, user_id) select 3, user_id from Temp
The above solution will work im almost all DBs

Get intersecting rows based on a column value

I have a table in SQL Server.This is how data is stored currently in table:
I want to get all common menu_id when multiple role_id are provided.
For eg: I want menu_id 1 when role_id provided are 1 and 3 as menu_id 1 is common for all role_id specified. I have no clue what query should I use. Can anyone help me?
Thanks in advance!
You seem to want menu_ids that have a list of role_id values. This should do what you want:
select menu_id
from t
where role_id in (1, 3)
group by menu_id
having count(*) = 2; -- number of values in IN list
Here is a db<>fiddle.
use group by with having
select menu_id from tablename
group by menu_id
having count(distinct role_id)>1

SQLite: How would you rephrase the query?

I created a basic movie database and for that I'm working with SQLite.
I have a table, which looks like this:
CREATE TABLE movie_collection (
user_id INTEGER NOT NULL,
movie_id INTEGER NOT NULL,
PRIMARY KEY (user_id, movie_id),
FOREIGN KEY (user_id) REFERENCES user (id),
FOREIGN KEY (movie_id) REFERENCES movie (id)
)
As one simple task, I want to show one user (let's say user_id = 1) the whole movie collections, in which the actual user(user_id = 1) might or might not have some movie collection. I also have to prevent the multiple result sets, where more than one user have the same movie record in their collection, especially if this involves the actual user (user_id = 1) then he has the priority, that is if there are let's say 3 records as following:
user_id movie_id
-------- ---------
1 17
5 17
8 17
Then the result set must have the record (1, 17) and not other two.
For this task I wrote a sql query like this:
SELECT movie_collect.user_id, movie_collect.movie_id
FROM (
SELECT user_id, movie_id FROM movie_collection WHERE user_id = 1
UNION
SELECT user_id, movie_id FROM movie_collection WHERE user_id != 1 AND movie_id NOT IN (SELECT movie_id FROM movie_collection WHERE user_id = 1)
) AS movie_collect
Altough this query delivers pretty much that what I need, but just out of curiosity I wanted to ask, if someone else has an another idea to solve this problem.
Thank you.
The outer query is superfluous:
SELECT user_id, movie_id
FROM movie_collection
WHERE user_id = 1
UNION
SELECT user_id, movie_id
FROM movie_collection
WHERE user_id != 1
AND movie_id NOT IN (SELECT movie_id
FROM movie_collection
WHERE user_id = 1)
And UNION removes duplicates, so you do not need to check for uid in the second subquery:
SELECT user_id, movie_id
FROM movie_collection
WHERE user_id = 1
UNION
SELECT user_id, movie_id
FROM movie_collection
WHERE movie_id NOT IN (SELECT movie_id
FROM movie_collection
WHERE user_id = 1)
And the only difference between the two subqueries is the WHERE clause, so you can combine them:
SELECT user_id, movie_id
FROM movie_collection
WHERE user_id = 1
OR movie_id NOT IN (SELECT movie_id
FROM movie_collection
WHERE user_id = 1);