SQL All Possible Round Robin Combinations between two Tables - sql

given table:
create table Person( Name varchar(100) )
where Name is unique for all Persons
What SQL query can generate all possible n!/((n-2)!2!) round robin combinations?
It is assumed that the cardinality of Person is ALWAYS equal to 4
Example Person = {'Anna','Jerome','Patrick','Michael')
Output:
Anna, Jerome
Anna, Patrick
Anna, Michael
Jerome, Patrick
Jerome, Michael
Patrick, Michael
Any help would be appreciated. Thanks!
Here's my answer (I used oracle SQL):
select P1.NAME PERSON1, P2.NAME PERSON2
from (select rownum RNUM, NAME
from PERSON) P1,
(select rownum RNUM, NAME
from PERSON) P2
where P1.RNUM < P2.RNUM

Here are two solutions for the problem
SELECT t1.Name + ',' + t2.Name AS NamesCombination
FROM Person t1
INNER JOIN Person t2
ON t1.Name < t2.Name
OR (Oracle 11i R2+)
WITH NamesCombination AS
(
SELECT 1 AS Cntr
,Name
, CAST(Name AS VARCHAR(MAX))AS NamesCombinations
FROM Person
UNION ALL
SELECT
nc.Cntr+1
,p.Name
,nc.NamesCombinations + ',' + CAST(p.Name AS VARCHAR(MAX))
FROM Person AS p JOIN NamesCombination nc ON p.Name < nc.Name
WHERE nc.Cntr < 2
)
SELECT NamesCombinations
FROM NamesCombination
WHERE Cntr = 2

select P1.NAME PERSON1, P2.NAME PERSON2
from (select rownum RNUM, NAME
from PERSON) P1,
(select rownum RNUM, NAME
from PERSON) P2
where P1.RNUM < P2.RNUM

Note that this is TSQL (Sql Server) syntax. I know that Oracle supports windowing functions, particularly row_number(), which is necessary for this solution.
It shouldn't be too hard to get this to work in Oracle with some trial and error
select p1.name, p2.name
from
(
select name, row_number() over(order by name) as rownumber
from person
) p1
inner join
(
select name, row_number() over(order by name) as rownumber
from person
) p2
on p1.name <> p2.name
and p1.rownumber > p2.rownumber
order by 1
row_number assigns a row number to each row. You then need to join, as suggested before, with the additional join clause of p1.rownumber > p2.rownumber

Related

Find the latest or earliest date

I have a table with a foreign key called team_ID, a date column called game_date, and a single char column called result. I need to find when the next volleyball game happens. I have successfully narrowed the game dates down to all the volleyball games that have not happened yet because the result IS NULL. I have all the select in line, I just need to find the earliest date.
Here is what I've got:
SELECT game.game_date, team.team_name
FROM game
JOIN team
ON team.team_id = game.team_id
WHERE team.sport_id IN
(SELECT sport.sport_id
FROM sport
WHERE UPPER(sport.sport_type_code) IN
(SELECT UPPER(sport_type.sport_type_code)
FROM sport_type
WHERE UPPER(sport_type_name) like UPPER('%VOLLEYBALL%')
)
)
AND game.result IS NULL;
I'm a time traveler so don't mind the old dates.
When I run it, I get this:
GAME_DATE TEAM_NAME
----------- ----------
11-NOV-1998 BEars
13-NOV-1998 BEars
13-NOV-1998 WildCats
14-NOV-1998 BEars
How do I set it up so I get only the MIN(DATE) and the TEAM_NAME playing on that date?
I've tried AND game.game_date = MIN(game.game_date) but it simply tells me that a group function in not allowed here. There has to be a way to retrieve the MIN(game_date) and use it as a condition to be met.
I'm using Oracle 11g pl/sql.
This should be the final working code.
SELECT *
FROM
(
SELECT g.game_date, t.team_name
FROM game g
JOIN team t
ON t.team_id = g.team_id
JOIN sport s
ON t.sport_id = s.sport_id
JOIN sport_type st
ON UPPER(s.sport_type_code) IN UPPER(st.sport_type_code)
WHERE UPPER(sport_type_name) like UPPER('%VOLLEYBALL%')
AND g.result IS NULL
ORDER BY g.game_date
)
WHERE ROWNUM = 1;
The ROWNUM pseudocolumn is generated before any ORDER BY clause is applied to the query. If you just do WHERE ROWNUM <= X then you will get X rows in whatever order Oracle produces the data from the datafiles and not the X minimum rows. To guarantee getting the minimum row you need to use ORDER BY first and then filter on ROWNUM like this:
SELECT *
FROM (
SELECT g.game_date, t.team_name
FROM game g
JOIN team t
ON t.team_id = g.team_id
INNER JOIN sport s
ON t.sport_id = s.sport_id
INNER JOIN sport_type y
ON UPPER( s.sport_type_code ) = UPPER( y.sport_type_code )
WHERE UPPER( y.sport_type_name) LIKE UPPER('%VOLLEYBALL%')
AND g.result IS NULL
ORDER BY game_date ASC -- You need to do the ORDER BY in an inner query
)
WHERE ROWNUM = 1; -- Then filter on ROWNUM in an outer query.
If you want to return multiple rows with the minimum date then:
SELECT game_date,
team_name
FROM (
SELECT g.game_date,
t.team_name,
RANK() OVER ( ORDER BY g.game_date ASC ) AS rnk
FROM game g
JOIN team t
ON t.team_id = g.team_id
INNER JOIN sport s
ON t.sport_id = s.sport_id
INNER JOIN sport_type y
ON UPPER( s.sport_type_code ) = UPPER( y.sport_type_code )
WHERE UPPER( y.sport_type_name) LIKE UPPER('%VOLLEYBALL%')
AND g.result IS NULL
)
WHERE rnk = 1;
Could you make it simple and order by date and SELECT TOP 1? I think this is the syntax in Oracle:
WHERE ROWNUM <= number;
select game.game_date,team.team_name from (
SELECT game.game_date, team.team_name, rank() over (partition by team.team_name order by game.game_date asc) T
FROM game
JOIN team
ON team.team_id = game.team_id
WHERE team.sport_id IN
(SELECT sport.sport_id
FROM sport
WHERE UPPER(sport.sport_type_code) IN
(SELECT UPPER(sport_type.sport_type_code)
FROM sport_type
WHERE UPPER(sport_type_name) like UPPER('%VOLLEYBALL%')
)
)
AND game.result IS NULL
) query1 where query1.T=1;

SQL SUBQUERY ON SELF

I have a table with the following data:
licence_number
date_of_birth
organisation
I want to do a query where:
Get the licence_numbers and dobs in organisation1 where the same
licence numbers and dobs are in organisation2.
I know it cant be that hard, but im struggling.
You can group by license_number and date_of_birth where organization is set to either of the two interesting organizations, and count how many distinct organizations there are in a group.
If there are two out of two possible in a single group, you have a hit.
SELECT license_number, date_of_birth
FROM mytable
WHERE organisation IN ('organisation1', 'organisation2')
GROUP BY license_number, date_of_birth
HAVING COUNT(DISTINCT organisation) = 2;
...or you can use INTERSECT;
SELECT license_number, date_of_birth
FROM mytable WHERE organisation = 'organisation1'
INTERSECT
SELECT license_number, date_of_birth
FROM mytable WHERE organisation = 'organisation2'
An SQLfiddle to test both.
select
from t t0
where
organization = 'organization1'
and
exists (
select 1
from t
where
organization = 'organization2'
and
licence_number = t0.licence_number
and
date_of_birth = t0.date_of_birth
)
You can just self join the table where the licence number and the dates are the same but the organisation isn't:
SELECT DISTINCT p1.licence_number, p1.date_of_birth
FROM people p1
INNER JOIN people p2
ON p1.licence_number = p2.licence_number AND
p1.date_of_birth = p2.date_of_birth AND
p1.organisation <> p2.organisation
SQL Fiddle here
Is it a JOIN or 1 table?
Select
[licence_number],
[date_of_birth],
[organisation]
From YourTable
Where organisation1 = organisation2
--OR
Select
[licence_number],
[date_of_birth],
[organisation]
From YourTable
Where organisation1 IN ('organisation2','organisation3','organisation3')
Order By [licence_number]

Query to find mutual likes?

I have a table which has the id of a particular person and id of the person he likes.
Likes
(p1,p2)
id1,id2
id2,id1
id3,id4
id3 id5
expected output
id1,id2
I have to remove duplicates also meaning id1,id2 to be returned once.
It is a exercise question.
select hh.id, hh.name, hh.grade as gr
, hh.id2, kk.name, kk.grade as gr1
from ( select id, id2, grade, name
from highschooler ab
, Likes cd
where ab.id = cd.id1 ) hh
, highschooler kk
where hh.id2 = kk.id
This query returns something like this
student id,student name,student grade,friend student likes,friend name,friend grade
This should do it joining on itself:
SELECT p.p1, p.p2
FROM Likes p
INNER JOIN Likes p2 ON
p.p1=p2.p2 AND
p.p2=p2.p1 AND
p.p1<p2.p1
Sample Fiddle Demo
I think the nicest way to do this is with a group by. In SQL Server, this requires using a case statement:
with l as (
select (case when p1 < p2 then p1 else p2 end) as pfirst,
(case when p1 < p2 then p2 else p1 end) as psecond
from likes
)
select pfirst, psecond
from l
group by pfirst, psecond
having count(*) = 2
If you have duplicates in the original data, then the having clause should be:
having count(distinct p1) = 2

SQL query for finding row with same column values that was created most recently

If I have three columns in my MySQL table people, say id, name, created where name is a string and created is a timestamp.. what's the appropriate query for a scenario where I have 10 rows and each row has a record with a name. The names could have a unique id, but a similar name none the less. So you can have three Bob's, two Mary's, one Jack and 4 Phil's.
There is also a hobbies table with the columns id, hobby, person_id.
Basically I want a query that will do the following:
Return all of the people with zero hobbies, but only check by the latest distinct person created, if that makes sense. Meaning if there is a Bob person that was created yesterday, and one created today.. I only want to know if the Bob created today has zero hobbies. The one from yesterday is no longer relevant.
select pp.id
from people pp, (select name, max(created) from people group by name) p
where pp.name = p.name
and pp.created = p.created
and id not in ( select person_id from hobbies )
SELECT latest_person.* FROM (
SELECT p1.* FROM people p1
WHERE NOT EXISTS (
SELECT * FROM people p2
WHERE p1.name = p2.name AND p1.created < p2.created
)
) AS latest_person
LEFT OUTER JOIN hobbies h ON h.person_id = latest_person.id
WHERE h.id IS NULL;
Try This:
Select *
From people p
Where timeStamp =
(Select Max(timestamp)
From people
Where name = p.Name
And not exists
(Select * From hobbies
Where person_id = p.id))

Help with query

I'm trying to make a query that looks at a single table to see if a student is in a team called CMHT and in a medic team - if they are I don't want to see the result.
I only want see the record if they're only in CMHT or medic, not both.
Would the right direction be using sub query to filter it out? I've done a search on NOT IN but how could you get to see check if its in more then 2 teams are not?
Student Team ref
1 CMHT 1
1 Medic 2
2 Medic 3 this would be in the result
3 CMHT 5 this would be in the result
So far I've done the following code would I need use a sub query or do a self join and filter it that way?
SELECT Table1.Student, Table1.Team, Table1.refnumber
FROM Table1
WHERE (((Table1.Team) In ('Medics','CMHT'))
This is Mark Byers's answer with a HAVING clause instead of a subquery:
SELECT Student, Team, ref
FROM Table1
GROUP BY Student
HAVING COUNT(Student) = 1
SELECT *
FROM students
WHERE NOT EXISTS
(
SELECT NULL
FROM students si
WHERE si.student = s.student
AND si.team = 'CMHT'
)
OR NOT EXISTS
(
SELECT NULL
FROM students si
WHERE si.student = s.student
AND si.team = 'Medic'
)
SELECT a.*
FROM Table1 a
INNER JOIN
( SELECT Student, COUNT(*) FROM Table1
GROUP BY Student
HAVING COUNT(*) = 1)b
ON (a.Student = b.Student)
how could you get to see check if its in 2 or more teams?
You can count the number of teams per student and then filter only those you want to see:
SELECT student FROM
(
SELECT student, COUNT(*) AS cnt
FROM Table1
GROUP BY student
) T1
WHERE cnt = 1
You can do it with outer join
select COALESCE(t1.Student, t2.Student) as Student,
COALESCE(t1.Team, t2.Team) as Team,
COALESCE(t1.ref, t2.ref) as ref
from
(select * from Student where Team = 'CMHT') t1
outer join
(select * from Student where Team = 'Medic') t2
on t1.Student = t2.Student
where
t1.Student is null or
t2.Student is null;