SQL - Select pairs of users with equal count - sql

I'm trying to write a query that returns pairs of users that have the same number of loans.
I have this table:
LOANS
id_loan book_barcode id_user
1 123 1
2 321 2
3 456 3
4 678 4
5 721 1
6 934 2
That's my code how to get pairs of users:
SELECT l1.id_user user_1, l2.id_user user_2
FROM loans l1
JOIN loans l2 ON l2.id_user > l2.id_user
GROUP BY l2.id_user, l2.id_user;
This is what I want from my query, but I don't know how to compare in the right way two counts, I tried but it didn't work.
id_user1 id_user2 number_loan
1 2 2
3 4 1

The most reasonable way is to aggregate the loans before joining:
with u as (
select id_user, count(*) as num_loans
from loans l
group by id_user
)
select u1.id_user, u2.id_user
from u u1 join
u u2
on u1.num_loans = u2.num_loans and u1.id_user < u2.id_user;
You could do this without pre-aggregating, but the query will be much more expensive:
select u1.id_user, u2.id_user
from loans u1 join
loans u2
on u1.id_user < u2.id_user
group by u1.id_user, u2.id_user
having count(distinct u1.id_loan) = count(distinct u2.id_loan);
I don't recommend this approach.

Related

i want to get the values from two tables

i got two tables
office accnt id
------------------------------
HR poop 1
HR fart 2
EXEC poop 3
and
id number
-----------------------
1 2
1 2
1 1
2 5
2 1
3 6
and what i wanted to be the output is like this
id office accnt number
--------------------------------------------
1 HR poop 5
2 HR fart 6
3 EXEC poop 6
and here's what I've tried so far
SELECT AccntTbl.office, AccntTbl.accnt, SUM(NumberTbl.Number)
FROM AccntTbl INNER JOIN
NumberTbl ON AccntTbl.Id = NumberTbl.Id
and sadly i can't get what i want..glad for any help.. :)
select a.id, a.office, a.accnt, SUM(n.Number)
from AccntTbl a INNER JOIN
NumberTbl n ON a.AccntTbl.Id = NumberTbl.Id
SELECT Accnt.id,Accnt.office, Accnt.accnt, SUM(Num.Number)
FROM AccntTbl Accnt INNER JOIN
NumberTbl Num ON Accnt.Id = Num.Id
It just needs a GROUP BY with the id, the office and the accnt.
SELECT
acc.id, acc.office, acc.accnt,
SUM(num.Number) AS number
FROM AccntTbl acc
JOIN NumberTbl num
ON acc.Id = num.Id
GROUP BY
acc.id, acc.office, acc.accnt

Group by with two columns

I am trying to write a query using group by in sub query ,I referred lot of blogs but could not get all the values.
I have three tables and below is the structure of those tables.
Pet_Seller_Master
ps_id ps_name city_id
2 abc 1
3 xyz 2
4 fer 4
5 bbb 1
City_Master
city_id city_name
1 Bangalore
2 COIMBATORE
4 MYSORE
Api_Entry
api_id ps_id otp
1 2 yes
2 3
3 2 yes
4 3 yes
5 4
6 5 yes
7 5 yes
8 5 yes
Query is to get number of sellers, no of pet sellers with zero otp, no of pet sellers with 1 otp, no of pet sellers with 2 otp,no of pet sellers with otp>2 for the particular city and within date range.
Through Below query I am able to get city , psp , and zero otp
select cm.city_name,
count(ps.ps_id) as PSP,
((select count(ps1.ps_id)
FROM ps_master ps1
WHERE ps1.city = cm.city_id)-
(SELECT count(distinct ps1.ps_id)
from ps_master ps1
INNER JOIN api_entry ae ON ps1.ps_id = ae.ps_id and otp!=''
WHERE ps1.city = cm.city_id and date(timestamp) >= curdate() - INTERVAL DAYOFWEEK(curdate())+6 DAY AND date(timestamp) < curdate())) as zero_psp
from ps_master ps INNER JOIN city_master cm ON ps.city = cm.city_id and cm.city_type = 'IN HOUSE PNS'
group by city_id
Please tell me the solution to solve this query.
Thanks in advance
It's not hard to do and you were on a right track. Here is what I would use:
select c.city_name, a.otp, p.ps_name, COUNT(*) nbr
from Api_Entry a
inner join Pet_Seller_Master p on p.ps_id=a.ps_id
inner join City_Master c on p.city_id=c.city_id
group by c.city_name, a.otp, p.ps_name
Now, if you want to get the number of sellers with zero otp, you just apply where clause:
where otp <> 'yes'
If you want to get the number of pet sellers with otp>2, then you just use subquery:
select *
from (
select c.city_name, a.otp, p.ps_name, COUNT(*) nbr
from #tempA a
inner join #tempP p on p.ps_id=a.ps_id
inner join #tempC c on p.city_id=c.city_id
group by c.city_name, a.otp, p.ps_name
) g
where nbr > 2

SQL - 3 level hierarchy query with CONNECT BY?

Say you have a 3 level hierarchy as follows: Household (1-m) --> Person (1-m) --> Account
But there are only 2 Tables:
Person (3 columns are):
Person_id, person_name, household_key
and
Account (3 columns are):
Account_id, account_name, person_id
What are some ways to get a query that returns these results (ie ordered by household, person then account):
Household_key Person_id Account_id
1 1 456
1 2 763
1 2 801
1 2 822
2 3 54
2 4 68
Judging from the desired result that doesn't look like a hierarchy query to me - try
SELECT DISTINCT
P.Household_key,
P.Person_id,
A.Account_id
FROM
Person P
INNER JOIN Account A ON P.Person_id = A.Person_id
ORDER BY
P.Household_key,
P.Person_id,
A.Account_id
IF I am mistaken THEN you will need to show some sample data in the tables Person and Account .

max count with joins

I have 3 tables:
users:
Id Login
1 John
2 Bill
3 Jim
computers:
Id Name
1 Computer1
2 Computer2
3 Computer3
4 Computer4
5 Computer5
sessions:
UserId ComputerId Minutes
1 2 47
2 1 32
1 4 15
2 5 5
1 2 7
1 1 40
2 5 31
I would like to display this resulting table:
Login Total_sess Total_min Most_freq_computer Sess_on_most_freq Min_on_most_freq
John 4 109 Computer2 2 54
Bill 3 68 Computer5 2 36
Jim - - - - -
Myself I can only cover first 3 columns with:
SELECT Login, COUNT(sessions.UserId), SUM(Minutes) FROM users
LEFT JOIN sessions
ON users.Id = sessions.UserId GROUP BY users.Id
And some kind of other columns with:
SELECT main.*
FROM (SELECT UserId, ComputerId, COUNT(*) AS cnt ,SUM(Minutes)
FROM sessions
GROUP BY UserId, ComputerId) AS main
INNER JOIN (
SELECT ComputerId, MAX(cnt) AS maxCnt FROM (
SELECT ComputerId, UserId, COUNT(*) AS cnt FROM sessions GROUP BY ComputerId, UserId
)
AS Counts GROUP BY ComputerId)
AS maxes
ON main.ComputerId = maxes.ComputerId
AND main.cnt = maxes.maxCnt
But I need to get whole resulting table in one query. I feel I'm doing something completely wrong. Need help.
Here you are:
SELECT u.login, t1.total_sess, t1.total_min, t2.mf, t2.sess_mf, t2.min_mf
FROM users u
LEFT JOIN (
SELECT userid, COUNT(minutes) AS total_sess, SUM(minutes) AS total_min
FROM sessions
GROUP BY userid
) AS t1 ON t1.userid = u.id
LEFT JOIN (
SELECT userid, name AS mf, COUNT(*) AS sess_mf, SUM(minutes) AS min_mf
FROM sessions s
JOIN computers c ON c.id = s.computerid
GROUP BY userid, computerid
HAVING COUNT(computerid) >= ALL(SELECT COUNT(*)
FROM sessions s2
WHERE s2.userid = s.userid
GROUP BY s2.computerid)
) AS t2 ON t2.userid = u.id
I'm using MySQL syntax, but it should be pretty portable.
If you need anything more, feel free to ask!
EDIT: I updated the query, the previous one was wrong :(

SQL: Select from many-many through, joined on conditions in through table

Can't get my head around this...
I have 3 tables like this:
Computers
---------
Id
Name
ComputerLogins
--------------
Computer_Id
User_Id
NumberOfLogins
Users
-----
Id
Name
Computers "have and belong to many" Users "through" ComputerLogins.
Sample data:
Computers: Id Name
1 "Alpha"
2 "Beta"
3 "Gamma"
Users: Id Name
1 "Joe"
2 "Fred"
ComputerLogins: Computer_Id User_Id NumberOfLogins
1 1 5
1 2 12
2 1 10
2 2 6
3 1 2
3 2 4
I'm trying to construct a view that will output one row for each record in Computers, and join a Users row through MAX(NumberOfLogins) in ComputerLogins.
Desired output:
Computer_Id User_Id NumberOfLogins
1 2 12
2 1 10
3 2 4
Can you suggest a view query that will produce the desired output?
Thanks!
SELECT
CL.*, U.* --change this as needed
FROM
(
SELECT
Computer_ID, MAX(NumberOfLogins) AS NumberOfLogins
FROM
ComputerLogins
GROUP BY
Computer_ID
) maxC
JOIN
ComputerLogins CL On maxC.Computer_ID = CL.Computer_ID AND maxC.NumberOfLogins = CL.NumberOfLogins
JOIN
Users U On CL.User_ID = U.ID
Wrap in a view etc
Use:
CREATE VIEW your_view AS
SELECT c.id AS computer_id,
u.id AS user_id,
COUNT(*) AS NumberOfLogins
FROM COMPUTERS c
JOIN COMPUTERLOGINS cl ON cl.computer_id = c.id
JOIN USERS u ON u.id = cl.user_id
GROUP BY c.id, u.id