Find the latest or earliest date - sql
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;
Related
How to create cases for multiple purposes and just showing the count of unique IDs for multiple cases
I wrote a CTE which helps determine a flag based off a certain client's ID and what kind of client they are. I am looking to test the counts of the Flags, and the counts are totaling out amazingly! However, I am looking to add additional columns to the very last section of my code to show the amount of IDs who have belonged in all 3 cases, or both PPP and R, PPP and RR, RR and PPP, or RR and R. Is there a way I could do this? I know SUM won't work. I'm thinking using CASE or an IF, however I am a novice to SQL and am unsure what to do. WITH ids AS ( SELECT DISTINCT LOWER(r.entry_id) AS ID FROM id_user AS r UNION SELECT DISTINCT LOWER(identifiervalue) AS ID FROM account AS a ) ,PPP as ( SELECT DISTINCT LOWER(accountid) as "ID" FROM ppp WHERE (date >= '2022-11-21') ) ,R as ( SELECT DISTINCT LOWER(account_id) as "ID" FROM user ) , RR as ( SELECT DISTINCT LOWER(id) AS "ID" FROM program_member ) , Joint as ( SELECT r.ID ,CASE WHEN p.ID IS NULL THEN 0 ELSE 1 END AS "PPP Flag" ,CASE WHEN r.ID IS NULL THEN 0 ELSE 1 END AS "R Flag" ,CASE WHEN rr.raid IS NULL THEN 0 ELSE 1 END AS "RR Flag" FROM ids i LEFT JOIN PPP ppp ON i.RAID = ppp.RAID LEFT JOIN R r ON i.RAID = r.RAID LEFT JOIN RR rr on i.RAID = rr.RAID ----TESTING COUNTS SELECT COUNT(ID) AS "ID Count" ,sum("PPP Flag") AS "PPP Users" ,sum("R") AS "R Accounts" ,sum("RR Flag") AS "RR Users" FROM Joint
if all you are trying to do is get distinct counts, and how many are within each of those given flag categories, dont try to repeat then join. They are either in the PPP, User or Program_Member table. Just get that select UnionCnt.IDAndRaidCnt, P.PPPCnt, R.RCnt, RR.RRCnt from -- this outer query returns only 1 record ( select count(*) IDAndRaidCnt from -- this inner query returns all distinct based on the UNION result (SELECT DISTINCT LOWER(r.entry_id) ID FROM id_user r UNION SELECT DISTINCT LOWER(identifiervalue) ID FROM account a) ) UnionCnt JOIN (SELECT count( DISTINCT LOWER(accountid)) PPPCnt FROM ppp WHERE date >= '2022-11-21' ) P -- above will only return a single record anyhow on 1=1 JOIN (SELECT count( DISTINCT LOWER(account_id) RCnt FROM user ) R -- also returns single row with total qualifying distinct ID count on 1=1 JOIN (SELECT count( DISTINCT LOWER(id)) RRCnt FROM program_member ) RR -- same here, single record on 1=1
How to do order by min() of some column?
I am pretty new to SQL. I want a query which should do order by on min of some column. Below is the query i want. SELECT * FROM ( SELECT p.PROJECT_ID, p.PROJECT_NAME, p.PROJECT_TYPE FROM PROJECT p LEFT OUTER JOIN code c ON p.PROJECT_ID= c.PROJECT_ID WHERE p.PROJECT_NAME IN ('test') ORDER BY min(c.LABEL) ASC ) WHERE rownum <= 25; Why i need it this way is. I have one table PROJECT. PROJECT_ID PROJECT_NAME PROJECT_TYPE 1 a test1 2 b test2 i have another table code which has project_id as foreign key. ID PROJECT_ID LABEL 1 1 a 2 1 b 3 1 c 4 2 d now when i will join it on project_id and make order by on code.label it will give me 4 records three with project id 1 and 1 with project id 2. But my requirement is to sort the project based on the codes label. so logically i want two records . One for project id 1 with min vale of label of all the possible combinations of project id 1 i.e with label a and other with project id 2. So that's why i want to sort it based on min of code label. I cannot use group by as it will degrade the performance.
For use a MIN( ) you need a group by eg: SELECT * FROM ( SELECT p.PROJECT_ID, p.PROJECT_NAME, p.PROJECT_TYPE FROM PROJECT p LEFT OUTER JOIN code c ON p.codeId=c.ID WHERE p.PROJECT_NAME IN ('test') GROUP BY .PROJECT_ID, p.PROJECT_NAME, p.PROJECT_TYPE ORDER BY min(c.LABEL) ASC ) WHERE rownum <= 25; and in some db you must select the column you need for order by eg: SELECT * FROM ( SELECT p.PROJECT_ID, p.PROJECT_NAME, p.PROJECT_TYPE, min(c.LABEL) FROM PROJECT p LEFT OUTER JOIN code c ON p.codeId=c.ID WHERE p.PROJECT_NAME IN ('test') GROUP BY .PROJECT_ID, p.PROJECT_NAME, p.PROJECT_TYPE ORDER BY min(c.LABEL) ASC ) WHERE rownum <= 25;
SQL - Select highest value when data across 3 tables
I have 3 tables: Person (with a column PersonKey) Telephone (with columns Tel_NumberKey, Tel_Number, Tel_NumberType e.g. 1=home, 2=mobile) xref_Person+Telephone (columns PersonKey, Tel_NumberKey, CreatedDate, ModifiedDate) I'm looking to get the most recent (e.g. the highest Tel_NumberKey) from the xref_Person+Telephone for each Person and use that Tel_NumberKey to get the actual Tel_Number from the Telephone table. The problem I am having is that I keep getting duplicates for the same Tel_NumberKey. I also need to be sure I get both the home and mobile from the Telephone table, which I've been looking to do via 2 individual joins for each Tel_NumberType - again getting duplicates. Been trying the following but to no avail: -- For HOME SELECT p.PersonKey, pn.Phone_Number, pn.Tel_NumberKey FROM Persons AS p INNER JOIN xref_Person+Telephone AS x ON p.PersonKey = x.PersonKey INNER JOIN Telephone AS pn ON x.Tel_NumberKey = pn.Tel_NumberKey WHERE pn.Tel_NumberType = 1 -- e.g. Home phone number AND pn.Tel_NumberKey = (SELECT MAX(pn1.Tel_NumberKey) AS Tel_NumberKey FROM Person AS p1 INNER JOIN xref_Person+Telephone AS x1 ON p1.PersonKey = x1.PersonKey INNER JOIN Telephone AS pn1 ON x1.Tel_NumberKey = pn1.Tel_NumberKey WHERE pn1.Tel_NumberType = 1 AND p1.PersonKey = p.PersonKey AND pn1.Tel_Number = pn.Tel_Number) ORDER BY p.PersonKey And have been looking over the following links but again keep getting duplicates. SQL select max(date) and corresponding value How can I SELECT rows with MAX(Column value), DISTINCT by another column in SQL? SQL Server: SELECT only the rows with MAX(DATE) Am sure this must be possible but been at this a couple of days and can't believe its that difficult to get the most recent / highest value when referencing 3 tables. Any help greatly appreciated.
select * from ( SELECT p.PersonKey, pn.Phone_Number, pn.Tel_NumberKey , row_number() over (partition by p.PersonKey, pn.Phone_Number order by pn.Tel_NumberKey desc) rn FROM Persons AS p INNER JOIN xref_Person+Telephone AS x ON p.PersonKey = x.PersonKey INNER JOIN Telephone AS pn ON x.Tel_NumberKey = pn.Tel_NumberKey WHERE pn.Tel_NumberType = 1 ) tt where tt.rn = 1 ORDER BY tt.PersonKey
you have to use max() function and then you have to order by rownum in descending order like. select f.empno from(select max(empno) empno from emp e group by rownum)f order by rownum desc It will give you all employees having highest employee number to lowest employee number. Now implement it with your case then let me know.
Complex SQL query with multiple tables and relations
In this Query, I have to list pair of players with their playerID and playerName who play for the exact same teams.If a player plays for 3 teams, the other has to play for exact same 3 teams. No less, no more. If two players currently do not play for any team, they should also be included. The query should return (playerID1, playername1, playerID2, playerName2) with no repetition such as if player 1 info comes before player 2, there should not be another tuple with player 2 info coming before player 1. For example if player A plays for yankees and redsox, and player b plays for Yankees, Red Sox, and Dodgers I should not get them. They both have to play for Yankees, and Red Sox and no one else. Right now this query finds answer if players play for any same team. Tables: player(playerID: integer, playerName: string) team(teamID: integer, teamName: string, sport: string) plays(playerID: integer, teamID: integer) Example data: PLAYER playerID playerName 1 Rondo 2 Allen 3 Pierce 4 Garnett 5 Perkins TEAM teamID teamName sport 1 Celtics Basketball 2 Lakers Basketball 3 Patriots Football 4 Red Sox Baseball 5 Bulls Basketball PLAYS playerID TeamID 1 1 1 2 1 3 2 1 2 3 3 1 3 3 So I should get this as answer- 2, Allen, 3, Pierce 4, Garnett, 5, Perkins . 2, Allen, 3 Pierce is an snwer because both play for exclusively CELTICS and PATRIOTS 4, Garnett, 5, Perkins iss an answer because both players play for no teams which should be in output. Right now the Query I have is SELECT p1.PLAYERID, f1.PLAYERNAME, p2.PLAYERID, f2.PLAYERNAME FROM PLAYER f1, PLAYER f2, PLAYS p1 FULL OUTER JOIN PLAYS p2 ON p1.PLAYERID < p2.PLAYERID AND p1.TEAMID = p2.TEAMID GROUP BY p1.PLAYERID, f1.PLAYERID, p2.PLAYERID, f2.PLAYERID HAVING Count(p1.PLAYERID) = Count(*) AND Count(p2.PLAYERID) = Count(*) AND p1.PLAYERID = f1.PLAYERID AND p2.PLAYERID = f2.PLAYERID; I am not 100% sure but I think this finds players who play for the same team but I want to find out players who play for the exclusively all same TEAMS as explained above I am stuck on how to approach it after this. Any hints on how to approach this problem. Thanks for your time.
I believe this query will do what you want: SELECT array_agg(players), player_teams FROM ( SELECT DISTINCT t1.t1player AS players, t1.player_teams FROM ( SELECT p.playerid AS t1id, concat(p.playerid,':', p.playername, ' ') AS t1player, array_agg(pl.teamid ORDER BY pl.teamid) AS player_teams FROM player p LEFT JOIN plays pl ON p.playerid = pl.playerid GROUP BY p.playerid, p.playername ) t1 INNER JOIN ( SELECT p.playerid AS t2id, array_agg(pl.teamid ORDER BY pl.teamid) AS player_teams FROM player p LEFT JOIN plays pl ON p.playerid = pl.playerid GROUP BY p.playerid, p.playername ) t2 ON t1.player_teams=t2.player_teams AND t1.t1id <> t2.t2id ) innerQuery GROUP BY player_teams Result: PLAYERS PLAYER_TEAMS 2:Allen,3:Pierce 1,3 4:Garnett,5:Perkins It uses array_agg over the teamid for each player in plays to match players with the exact same team configuration. I Included a column with the teams for example, but that can be removed without affecting the results as long as it isn't removed from the group by clause. SQL Fiddle example.Tested with Postgesql 9.2.4 EDIT: Fixed an error that duplicated rows.
Seems that OP probably won't be interested anymore, but in case somebody else finds it useful, this is query in pure SQL that works (for me at least ;)) SELECT M.p1, pr1.playername, M.p2, pr2.playername FROM player pr1 INNER JOIN player pr2 INNER JOIN ( SELECT plays1.player p1, plays2.player p2, plays1.team t1 FROM plays plays1 INNER JOIN plays plays2 ON (plays1.player < plays2.player AND plays1.team = plays2.team) GROUP BY plays1.player, plays2.player HAVING COUNT(*) = ((SELECT COUNT(*) FROM plays plays3 WHERE plays3.player = plays1.player) + (SELECT COUNT(*) FROM plays plays4 WHERE plays4.player = plays2.player)) /2 ) M ON pr1.playerID = M.p1 AND pr2.playerID = M.p2 UNION ALL SELECT M.pid, M.pname, N.pid2, N.pname2 FROM ( (SELECT p.playerID pid, p.playerName pname, pl.team FROM player p LEFT JOIN plays pl ON p.playerId = pl.player WHERE pl.team IS NULL) M INNER JOIN (SELECT p.playerID pid2, p.playerName pname2, pl.team FROM player p LEFT JOIN plays pl ON p.playerId = pl.player WHERE pl.team IS NULL) N ON (pid < pid2) )
its not any big deal, here is solution with gigo as(select a.playerid as playerid,count(b.teamname) as nteams from player a full outer join plays c on a.playerid=c.playerid full outer join team b on b.teamid=c.teamid group by a.playerid) select array_agg(a.*),g.nteams from player a inner join gigo g on a.playerid=g.playerid group by g.nteams having count(a.*)>1 order by g.nteams desc
This solution works for me : SELECT TMP1. PLAYERID,TMP2.PLAYERID FROM ( SELECT a.playerid , a.teamid,b.team_sum FROM plays A INNER JOIN ( SELECT PLAYERID,SUM(teamid) AS team_sum FROM plays GROUP BY 1 ) B ON a.playerid=b.playerid ) TMP1 INNER JOIN ( SELECT a.playerid , a.teamid,b.team_sum FROM plays A INNER JOIN ( SELECT PLAYERID,SUM(teamid) AS team_sum FROM plays GROUP BY 1 ) B ON a.playerid=b.playerid )TMP2 ON TMP1.PLAYERID < TMP2.PLAYERID AND TMP1.TEAMID=TMP2.TEAMID AND TMP1.TEAM_SUM=TMP2.TEAM_SUM GROUP BY 1,2 UNION ALL SELECT n1,n2 FROM ( SELECT TMP3.PLAYERID AS n1,TMP4.PLAYERID AS n2 FROM PLAYER TMP3 INNER JOIN PLAYER TMP4 ON TMP3.PLAYERID<TMP4.PLAYERID WHERE TMP3.PLAYERID NOT IN (SELECT PLAYERID FROM plays ) AND tmp4.playerid NOT IN (SELECT playerid FROM plays) ) TMP5
Two possible solutions come to mind: Cursor - Looping through each player and comparing him to all the others until reaching a conclusion. Recursive query - Same idea though slightly more complicated but defiantly the better way to do it. Probably also has better performance. Can you provide some sample data so that I can create an example?
It seems like the basic datatype you want is sets, rather than arrays. So one option may be to use PL/Python with code similar to that below (see bottom of this answer for a function that might be adapted to this end). Of course, this isn't a "pure SQL" approach by any means. But sticking to PostgreSQL (albeit not standard SQL), you may also want to use DISTINCT with array_agg. Note that the following only gives the first pair that meets the criteria (in principle there could be many more). WITH teams AS ( SELECT playerID, array_agg(DISTINCT teamID ORDER BY teamID) AS teams FROM plays GROUP BY playerID), teams_w_nulls AS ( SELECT a.playerID, b.teams FROM player AS a LEFT JOIN teams AS b ON a.playerID=b.playerID), player_sets AS ( SELECT teams, array_agg(DISTINCT playerID ORDER BY playerID) AS players FROM teams_w_nulls GROUP BY teams -- exclude players who are only share a team list with themselves. HAVING array_length(array_agg(DISTINCT playerID ORDER BY playerID),1)>1) SELECT a.teams, b.playerID, b.playerName, c.playerID, c.playerName FROM player_sets AS a INNER JOIN player AS b ON a.players[1]=b.playerID INNER JOIN player AS c ON a.players[2]=c.playerID; The query above gives the following output: teams | playerid | playername | playerid | playername -------+----------+------------+----------+------------ {1,3} | 2 | Allen | 3 | Pierce | 4 | Garnett | 5 | Perkins (2 rows) Example PL/Python functions: CREATE OR REPLACE FUNCTION set(the_list integer[]) RETURNS integer[] AS $BODY$ return list(set(the_list)) $BODY$ LANGUAGE plpython2u; CREATE OR REPLACE FUNCTION pairs(a_set integer[]) RETURNS SETOF integer[] AS $BODY$ def pairs(x): for i in range(len(x)): for j in x[i+1:]: yield [x[i], j] return list(pairs(a_set)) $BODY$ LANGUAGE plpython2u; SELECT set(ARRAY[1, 1, 2, 3, 4, 5, 6, 6]); Version of code above using these functions (output is similar, but this approach selects all pairs when there is more than one for a given set of teams): WITH teams AS ( SELECT playerID, set(array_agg(teamID)) AS teams FROM plays GROUP BY playerID), teams_w_nulls AS ( SELECT a.playerID, b.teams FROM player AS a LEFT JOIN teams AS b ON a.playerID=b.playerID), player_pairs AS ( SELECT teams, pairs(set(array_agg(playerID))) AS pairs FROM teams_w_nulls GROUP BY teams) -- no need to exclude players who are only share a team -- list with themselves. SELECT teams, pairs[1] AS player_1, pairs[2] AS player_2 FROM player_pairs;
We make a query with the count of the teams per player and sum of ascii(team_name)+team_id call it team_value. We do a self join, of the same query with itself where counts and team_values match but id not equal to id, that gives us the ID's we want to fetch select * from player where player_id in ( select set2.player_id orig from (select count(*) count,b.player_id , nvl(sum(a.team_id+ascii(team_name)),0) team_value from plays a, player b , team c where a.player_id(+)=b.player_id and a.team_id = c.team_id(+) group by b.player_id) set1, (select count(*) count,b.player_id , nvl(sum(a.team_id+ascii(team_name)),0) team_value from plays a, player b , team c where a.player_id(+)=b.player_id and a.team_id = c.team_id(+) group by b.player_id) set2 where set1.count=set2.count and set1.team_value=set2.team_value and set1.player_id<>set2.player_id )
Here is the simple query with UNION and 2-3 simple joins. 1st query before UNION contains player name and playerid who has played for same number of teams for equal number of times. 2nd query after UNION contains player name and playerid who has not played for any team at all. Simply copy paste this query and try to execute it, you will see the expected results. select playername,c.playerid from (select a.cnt, a.playerid from (select count(1) cnt , PLAYERID from plays group by PLAYERID) a , (select count(1) cnt , PLAYERID from plays group by PLAYERID) b where a.cnt=b.cnt and a.playerid<> b.playerid ) c ,PLAYER d where c.playerid=d.playerid UNION select e.playername,e.playerid from player e left outer join plays f on e.playerid=f.playerid where nvl(teamid,0 )=0
Try this one : Here test is PLAYS table in your question. select group_concat(b.name),a.teams from (SELECT playerid, group_concat(distinct teamid ORDER BY teamid) AS teams FROM test GROUP BY playerid) a, player b where a.playerid=b.playerid group by a.teams union select group_concat(c.name order by c.playerid),null from player c where c.playerid not in (select playerid from test);
For anyone interested, this simple query works for me SELECT UNIQUE PLR1.PID,PLR1.PNAME, PLR2.PID, PLR2.PNAME FROM PLAYS PLY1,PLAYS PLY2, PLAYER PLR1, PLAYER PLR2 WHERE PLR1.PID < PLR2.PID AND PLR1.PID = PLY1.PID(+) AND PLR2.PID = PLY2.PID(+) AND NOT EXISTS(( SELECT PLY3.TEAMID FROM PLAYS PLY3 WHERE PLY3.PID = PLR1.PID) MINUS ( SELECT PLY4.TEAMID FROM PLAYS PLY4 WHERE PLY4.PID = PLR2.PID));
select p1.playerId, p2.playerId, count(p1.playerId) from plays p1, plays p2 WHERE p1.playerId<p2.playerId and p1.teamId = p2.teamId GROUP BY p1.playerId, p2.playerId having count(*) = (select count(*) from plays where playerid = p1.playerid)
WITH temp AS ( SELECT p.playerid, p.playername, listagg(t.teamname,',') WITHIN GROUP (ORDER BY t.teamname) AS teams FROM player p full OUTER JOIN plays p1 ON p.playerid = p1.playerid LEFT JOIN team t ON p1.teamid = t.teamid GROUP BY (p.playerid , p.playername)) SELECT concat(concat(t1.playerid,','), t1.playername), t1.teams FROM temp t1 WHERE nvl(t1.teams,' ') IN ( SELECT nvl(t2.teams,' ') FROM temp t2 WHERE t1.playerid <> t2.playerid) ORDER BY t1.playerid
This is ANSI SQL , without using any special functions. SELECT TAB1.T1_playerID AS playerID1 , TAB1.playerName1 , TAB1.T2_playerID AS playerID2, TAB1. playerName2 FROM (select T1.playerID AS T1_playerID , T3. playerName AS playerName1 , T2.playerID AS T2_playerID , T4. playerName AS playerName2 ,COUNT (T1.TeamID) AS MATCHING_TEAM_ID_CNT FROM PLAYS T1 INNER JOIN PLAYS T2 ON( T1.TeamID = T2.TeamID AND T1.playerID <> T2.playerID ) INNER JOIN player T3 ON ( T1.playerID=T3.playerID) INNER JOIN player T4 ON ( T2.playerID=T4.playerID) GROUP BY 1,2,3,4 ) TAB1 INNER JOIN ( SELECT T1.playerID AS playerID, COUNT(T1.TeamID) AS TOTAL_TEAM_CNT FROM PLAYS T1 GROUP BY T1.playerID) TAB2 ON(TAB1.T2_playerID=TAB2.playerID AND TAB1.MATCHING_TEAM_ID_CNT =TAB2.TOTAL_TEAM_CNT) INNER JOIN ( SELECT T1.playerID AS playerID, COUNT(T1.TeamID) AS TOTAL_TEAM_CNT FROM PLAYS T1 GROUP BY T1.playerID ) TAB3 ON( TAB1. T1_playerID = TAB3.playerID AND TAB1.MATCHING_TEAM_ID_CNT=TAB3.TOTAL_TEAM_CNT) WHERE playerID1 < playerID2 UNION ALL ( SELECT T1.playerID, T1.playerName ,T2.playerID,T2.playerName FROM PLAYER T1 INNER JOIN PLAYER T2 ON (T1.playerID<T2.playerID) WHERE T1.playerID NOT IN ( SELECT playerID FROM PLAYS))
Assuming your teamId is unique this query will work. It simply identifies all players that have the exact same teams by summing the teamid or if the player has no ids it will be null. Then counts the number of matches over team matches. I tested using SQL fiddle in postgre 9.3. SELECT b.playerID ,b.playerName FROM ( --Join the totals of teams to your player information and then count over the team matches. SELECT p.playerID ,p.playerName ,m.TeamMatches ,COUNT(*) OVER(PARTITION BY TeamMatches) as Matches FROM player p LEFT JOIN ( --Assuming your teamID is unique as it should be. If it is then a sum of the team ids for a player will give you each team they play for. --If for some reason your team id is not unique then rank the table and join same as below. SELECT ps.playerName ,ps.playerID ,SUM(t.teamID) as TeamMatches FROM plays p LEFT JOIN team t ON p.teamID = p.teamID LEFT JOIN player ps ON p.playerID = ps.playerID GROUP BY ps.playerName ,ps.playerID ) m ON p.playerID = m.playerID ) b WHERE b.Matches <> 1
This Query should solve it. By doing a self join on PLAYS. - Compare on the player Id - Compare the matching row count with the total count for each player. select p1.playerId, p2.playerId, count(p1.playerId) from plays p1, plays p2 WHERE p1.playerId<p2.playerId and p1.teamId = p2.teamId GROUP BY p1.playerId, p2.playerId having count(*) = (select count(*) from plays where playerid = p1.playerid)
Create function in SQl 2008 ALTER FUNCTION [dbo].[fngetTeamIDs] ( #PayerID int ) RETURNS varchar(101) AS Begin declare #str varchar(1000) SELECT #str= coalesce(#str + ', ', '') + CAST(a.TeamID AS varchar(100)) FROM (SELECT DISTINCT TeamID from Plays where PayerId=#PayerID) a return #str END --select dbo.fngetTeamIDs(2) Query start here drop table #temp,#A,#B,#C,#D (select PayerID,count(*) count into #temp from Plays group by PayerID) select * into #A from #temp as T where T.count in ( select T1.count from #temp as T1 group by T1.count having count(T1.count)>1 ) select A.*,P.TeamID into #B from #A A inner join Plays P on A.PayerID=P.PayerID order by A.count select B.PayerId,B.count, ( select dbo.fngetTeamIDs(B.PayerId) ) as TeamIDs into #C from #B B group by B.PayerId,B.count select TeamIDs into #D from #c as C group by C.TeamIDs having count(C.TeamIDs)>1 select C.PayerId,P.PlayerName,D.TeamIDs from #D D inner join #C C on D.TeamIDs=C.TeamIDs inner join Player P on C.PayerID=P.PlayerID
How to display the record with the highest value in Oracle?
I have 4 tables with the following structure: Table artist: artistID lastname firstname nationality dateofbirth datedcease Table work: workId title copy medium description artist ID Table Trans: TransactionID Date Acquired Acquistionprice datesold askingprice salesprice customerID workID Table Customer: customerID lastname Firstname street city state zippostalcode country areacode phonenumber email First question is which artist has the most works of artsold and how many of the artist works have been sold. My SQL query is this: SELECT * From dtoohey.artist A1 INNER JOIN ( SELECT COUNT(W1.ArtistID) AS COUNTER, artistID FROM dtoohey.trans T1 INNER JOIN dtoohey.work W1 ON W1.workid = T1.Workid GROUP BY W1.artistID ) TEMP1 ON TEMP1.artistID = A1.artistID WHERE A1.artistID = TEMP1.artistId ORDER BY COUNTER desc; I am to get the whole table but I only want show only the first row which is the highest count how do I do that?? I have tried inserting WHERE ROWNUM <=1 but it shows artist ID with 1 qns 2 is sales of which artist's work have resulted in the highest average profit (i.e) the average of the profits made on each sale of worksby an artist), and what is that amount. My SQL query is: SELECT A1.artistid, A1.firstname FROM ( SELECT (salesPrice - AcquisitionPrice) as profit, w1.artistid as ArtistID FROM dtoohey.trans T1 INNER JOIN dtoohey.WORK W1 on W1.workid = T1.workid ) TEMP1 INNER JOIN dtoohey.artist A1 ON A1.artistID = TEMP1.artistID GROUP BY A1.artistid HAVING MAX(PROFIT) = AVG(PROFIT); I'm not able to execute it I have tried query below but still not able to get it keep getting the error missing right parenthesis SELECT A1.artistid, A1.firstname, TEMP1.avgProfit FROM ( SELECT AVG(salesPrice - AcquisitionPrice) as avgProfit, W1.artistid as artistid FROM dtoohey.trans T1 INNER JOIN dtoohey.WORK W1 ON W1.workid = T1.workid GROUP BY artistid ORDER BY avgProfit DESC LIMIT 1 ) TEMP1 INNER JOIN dtoohey.artist A1 ON A1.artisid = TEMP1.artistid
Sometimes ORA-00907: missing right parenthesis means exactly that: we have a left bracket without a matching right one. But it can also be thrown by a syntax error in a part of a statement bounded by parentheses. It's that second cause here: LIMIT is a Mysql command which Oracle does not recognise. You can use an analytic function here: SELECT A1.artistid, A1.firstname, TEMP1.avgProfit FROM ( select artistid , avgProfit , rank() over (order by avgProfit desc) as rnk from ( SELECT AVG(salesPrice - AcquisitionPrice) as avgProfit, W1.artistid as artistid FROM dtoohey.trans T1 INNER JOIN dtoohey.WORK W1 ON W1.workid = T1.workid GROUP BY artistid ) ) TEMP1 INNER JOIN dtoohey.artist A1 ON A1.artisid = TEMP1.artistid where TEMP1.rnk = 1 This uses the RANK() function which will return more than one row if several artists achieve the same average profit. You might want to use ROW_NUMBER() instead. Analytic functions can be very powerful. Find out more. You can apply ROWN_NUMBER(), RANK() and DENSE_RANK() to any top-n problem. You can use one of them to solve your first problem too. "however the avg profit is null." That's probably a data issue. If one of the numbers in (salesPrice - AcquisitionPrice) is null the result will be null, and won't be included in the average. If all the rows for an artist are null the AVG() will be null. As it happens the sort order will put NULL last. But as the PARTITION BY clause sorts by AvgProfit desc that puts the NULL results at rank 1. The solution is to use the NULLS LAST in the windowing clause: , rank() over (order by avgProfit desc nulls last) as rnk This will guarantee you a non-null result at the top (providing at least one of your artists has values in both columns).
1st question - Oracle does not guarantee the order by which rows are retrieved. Hence you must first order and then limit the ordered set. SELECT * from ( SELECT A1.* From dtoohey.artist A1 INNER JOIN ( SELECT COUNT(W1.ArtistID) AS COUNTER, artistID FROM dtoohey.trans T1 INNER JOIN dtoohey.work W1 ON W1.workid = T1.Workid GROUP BY W1.artistID ) TEMP1 ON TEMP1.artistID = A1.artistID WHERE A1.artistID = TEMP1.artistId ORDER BY COUNTER desc ) WHERE ROWNUM = 1 2nd question: I believe (haven't tested) that you have that LIMIT 1 wrong. That keyword is for use with Bulk collecting.