How to insert unique ID from subquery into a table? - sql

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

Related

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 do I get a count of records from one table with detail from another table

In Oracle I have two tables, USER and USER_DETAIL. The USER_DETAIL table has a foreign key link to the USER table, so pretty standard stuff. The USER table has among others USER_ID and ACCOUNT_NUM fields, and USER_DETAIL has further data such as USER_ID and IBAN.
The scenario is that multiple users can have the same IBAN. What I'm trying to do is create a query that shows where the same IBAN is being used by more than one user, with the number of users and the list of account numbers for each IBAN.
Db tables:
USER USER_DETAIL
________ ________
USER_ID ACCOUNT_NUM USER_ID IBAN
1, ACC001 1, IBAN001
2, ACC002 2
3, ACC003 3, IBAN002
4, ACC004 4, IBAN001
The query result I'm trying to achieve (showing that IBAN001 is being used by ACC001 and ACC004):
COUNT IBAN ACCOUNT_NUM
2 IBAN001 ACC001
ACC004
The part that's confusing me is the JOIN and GROUP BY. This works to get the count and IBAN:
SELECT COUNT(ud.user_id) AS num_users, ud.iban
FROM user_detail ud
WHERE ud.iban IS NOT NULL
GROUP BY iban
HAVING COUNT(ud.user_id) > 1
ORDER BY ud.iban
But when I try to join to the USER table and show all account numbers using each IBAN, I either get a "not a GROUP BY expression" error or the count is lost:
SELECT COUNT(ud.user_id) AS num_users, ud.iban, u.account_num
FROM user u
INNER JOIN user_detail ud USING (user_id)
WHERE ud.iban IS NOT NULL
GROUP BY ud.iban, u.account_num
HAVING COUNT(ud.user_id) > 1
ORDER BY ud.iban
If I understand correctly you want LISTAGG() to combine the accounts together in the aggregation results:
SELECT ud.iban, COUNT(*) as num_users,
LISTAGG(u.account_num, ',') WITHIN GROUP (ORDER BY u.account_num)
FROM user u INNER JOIN
user_detail ud
USING (user_id)
WHERE ud.iban IS NOT NULL
GROUP BY ud.iban
HAVING COUNT(*) > 1
ORDER BY ud.iban

Count companies with more than one contact

Select count (distinct company_id)
from contacts
group by company_id
having count(contact_id) >1) from contact
I used this query but output comes with list of rows and their contact with more than 2.
I looking for single digit like 6 as output.
It depends on the fine print! You commented:
there are some company_id with null, and have contact_id on them, I don't want to use NULL
So we exclude company_id IS NULL. Still unclear how to deal with contact_id IS NULL. Some options:
SELECT count(*)
FROM (
SELECT count(*) AS ct -- count all contacts
-- count(contact_id) AS ct -- count not-null contacts
-- count(DISTINCT contact_id) AS ct -- count not-null, distinct contacts
FROM contacts
WHERE company_id IS NOT NULL -- "I dont want to use NULL"
GROUP BY company_id
) t
WHERE ct > 1;
A HAVING clause in the subquery is equivalent. WHERE in the outer query is just simpler syntax.
select count(*) from
(
select company_id
from contacts
where company_id is not null
group by company_id
having count(distinct contact_id) > 1
) t;
If you are sure that all (company_id, contact_id) pairs are unique then count(distinct contact_id) becomes simply count(*)

Select everything, based on distinct USER ID in Oracle

I am trying to select * from an oracle table, but only where user_id are unique.
i tried this:
select distinct user_id from users; -- which worked
i want to display EVERYTHING, so when i put:
select distinct user_id, * from users; -- i get a syntax error
how can i accomplish his?
select distinct user_id, users.* from users;
select * from users where users.primary_key IN
(select primary_key FROM users GROUP BY user_id HAVING count(*) = 1)
This will only select records that do not share user_ids with other rows.

Find Specific Rows

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