displaying the top 3 rows - oracle

In the school assignment I'm working on I need to display the 3 criminals with the most crimes. But I'm having a few problems
Here's the code I have so far, and its output:
`Select Last, First, Count(Crime_ID)
From Criminals Natural Join crimes
Group by Last, First, Criminal_ID
order by Count(Crime_Id) Desc`
`LAST FIRST COUNT(CRIME_ID)
--------------- ---------- ---------------
Panner Lee 2
Sums Tammy 1
Statin Penny 1
Dabber Pat 1
Mansville Nancy 1
Cat Tommy 1
Phelps Sam 1
Caulk Dave 1
Simon Tim 1
Pints Reed 1
Perry Cart 1
11 rows selected `
I've been toying around with ROWNUM, but when I include it in the SELECT it won't run because of my GROUP BY. But If you put ROWNUM in the GROUP BY it just separates everything back out.
I just want to display the top 3 with the most crimes, which is weird because only 1 guy has more than 1 crime. Theoretically, more criminals would be added to the Database, but these are the tables given in the assignment.

select *
from
( Select Last, First, Count(Crime_ID)
From Criminals Natural Join crimes
Group by Last, First, Criminal_ID
order by Count(Crime_Id) Desc )
where ROWNUM <= 3;

Related

How to break a VARCHAR2(4000) string line in Multiple Rows Counting the Words Repetition

I have an Issues DataBase, with many solutions open/closed for each issue in a view.
My chalenge is take all the answers, break it in each words it as was writed, and count these words separeted by column for the entire number of issues stored in this Data Base (view).
Sample.:
SELECT * FROM VW_ISSUE_REPORT;
issueID
ProblemReported
Solution
IsClosed
1
Printer Offline
Turn On the Printer ABC
Yes
2
Printer Paper Jam
Remove Paper Jam from Printer ABC
No
Result expected: (This is a historical database, I can't create functions, procedures, etc. Just a smart, and well known SELECT statement.).
SELECT MAGIC_SOLUTION( Solution) AS SolutionKeyWord , COUNT('X') AS SolutionRepetitions FROM VW_ISSUE_REPORT GROUP BY MAGIC_SOLUTION( Solution);
SolutionKeyWord
SolutionRepetitions
ABC
2
Printer
2
from
1
Jam
1
On
1
Paper
1
Remove
1
the
1
Turn
1
Best Regards
As you can't (at least, I think you can't) distinguish "names" from "solutions" (i.e. how to remove "ABC" from result? It can be anything, from HP to Canon to its IP address), one option is to split the whole solution into rows and count how many times each of its words repeats.
Sample data:
SQL> with test (issue_id, problemreported, solution, isclosed) as
2 (select 1, 'Printer Offline', 'Turn On the Printer ABC', 'Yes' from dual union all
3 select 2, 'Printer Paper Jam', 'Remove Paper Jam from Printer ABC', 'No' from dual
4 )
Query begins here:
5 select regexp_substr(solution, '[^ ]+', 1, column_value) solution_keyword,
6 count(*) solution_repetitions
7 from test cross join
8 table(cast(multiset(select level from dual
9 connect by level <= regexp_count(solution, ' ') + 1
10 ) as sys.odcinumberlist))
11 group by regexp_substr(solution, '[^ ]+', 1, column_value);
SOLUTION_KEYWORD SOLUTION_REPETITIONS
--------------------------------- --------------------
Paper 1
Printer 2
Turn 1
the 1
Remove 1
Jam 1
On 1
from 1
ABC 2
9 rows selected.
SQL>

Oracle Query Prevent Displayed Duplicate Record

Let's say i have a table structure like this :
ID | Name | SCHOOLNAME | CODESCHOOL
1 DARK Kindergarten 123 1
2 DARK Kindergarten 111 1
3 Knight NY University 3
4 Knight LA Senior HS 2
5 JOHN HARVARD 3
so, how to diplay all of the data above into like this :
ID | Name | SCHOOLNAME | CODESCHOOL
1 DARK Kindergarten 123 1
3 Knight NY University 3
5 JOHN HARVARD 3
my purpose is want to display data with the max of codeschool, but when i tried with my query below :
SELECT NAME, SCHOOLNAME, MAX(CODESCHOOL) FROM TABLE GROUP BY NAME, SCHOOLNAME
but the result is just like this :
ID | Name | SCHOOLNAME | CODESCHOOL
1 DARK Kindergarten 123 1
2 DARK Kindergarten 111 1
3 Knight NY University 3
4 Knight LA Senior HS 2
5 JOHN HARVARD 3
maybe it caused by the GROUP BY SCHOOLNAME, when i tried to not select SCHOOLNAME, the data displayed just like what i expected, but i need the SCHOOLNAME field for search condition in my query
hope you guys can help me out of this problem
any help will be appreciated
thanks
Using some wacky joins you can get a functional get max rows per category query.
What you essentially need to do is to join the table to itself and make sure that the joined values only contain the top values for the CODESCHOOL column.
I've also added a :schoolname parameter because you wanted to search by schoolname
Example:
SELECT
A.*
FROM
TABLE1 A
LEFT OUTER JOIN TABLE1 B ON B.NAME = A.NAME
AND B.CODESCHOOL < A.CODESCHOOL
WHERE
B.CODESCHOOL IS NULL AND
(
(A.SCHOOLNAME = :SCHOOLNAME AND :SCHOOLNAME IS NOT NULL) OR
(:SCHOOLNAME IS NULL)
);
this should create this output, note that dark has 2 outputs because it has 2 rows with the same code school which is the max in the dark "category"/name.
ID|NAME |SCHOOLNAME |CODESCHOOL
--| -----|----------------|----------
4|Knight|LA Senior HS | 2
5|JOHN |HARVARD | 3
2|DARK |Kindergarten 111| 1
1|DARK |Kindergarten 123| 1
It's not the most effective query but it should be more than good enough as a starting point.
Sidenote: I've been blatantly stealing this logic for a while from https://www.xaprb.com/blog/2007/03/14/how-to-find-the-max-row-per-group-in-sql-without-subqueries/
I am using an analytical window function ROW_NUMBER().
This will group (or partition) by NAME then select the top 1 CODESCHOOL in DESC order.
Select NAME,
SCHOOLNAME,
CODESCHOOL
From (
Select NAME,
SCHOOLNAME,
CODESCHOOL,
ROW_NUMBER() OVER (PARTITION BY NAME ORDER BY CODESCHOOL DESC) as rn
from myTable)
Where rn = 1;

Select same column for different values on a different column

I did search the forum before posting this and found some topics which were close to the same issue but I still had questions so am posting it here.
EMP_ID SEQ_NR NAME
874830 3 JOHN
874830 4 JOE
874830 21 MIKE
874830 22 BILL
874830 23 ROBERT
874830 24 STEVE
874830 25 JERRY
My output should look like this.
EMP ID SEQ3NAME SEQ4NAME SEQ21NAME SEQ22NAME SEQ23NAME SEQ24NAME SEQ25NAME
874830 JOHN JOE MIKE BILL ROBERT STEVE JERRY
SELECT A.EMP_ID
,A.NAME SEQ3NAME
,B.NAME SEQ4NAME
FROM AC_XXXX_CONTACT A
INNER JOIN AC_XXXX_CONTACT B ON A.EMP_ID = B.EMP_ID
WHERE A.SEQ_NR = '03' AND B.SEQ_NR = '04'
AND B.EMP_ID = '874830';
The above query helped me get the below results.
EMP_ID SEQ3NAME SEQ4NAME
874830 JOHN JOE
My question is to get all the fields(i.e till seq nr = 25) should I be joining the table 5 more times.
Is there a better way to get the results ?
I m querying against the Oracle DB
Thanks for your help.
New Requirement
New Input
STU-ID SEM CRS-NBR
12345 1 100
12345 1 110
12345 2 200
New Output
stu-id crs1 crs2
12345 100 200
12345 110
Not tested since you didn't provide test data (from table AC_XXXX):
(using Oracle 11 PIVOT clause)
select *
from ( select emp_id, seq_nr, name
from ac_xxxx
where emp_id = '874830' )
pivot ( max(name) for seq_nr in (3 as seq3name, 4 as seq4name, 21 as seq21name,
22 as seq22name, 23 as seq23name, 24 as seq24name, 25 as seq25name)
)
;
For Oracle 10 or earlier, pivoting was done "by hand", like so:
select max(emp_id) as emp_id, -- Corrected based on comment from OP
max(case when seq_nr = 3 then name end) as seq3name,
max(case when seq_nr = 4 then name end) as seq4name,
-- etc. (similar expressions for the other seq_nr)
from ac_xxxx
where emp_id = '874830'
;
Or, emp_id doesn't need to be within max() if we add group by emp_id - which then will work even without the WHERE clause, for a different but related question.

Loop through a table in Oracle PL/SQL

I have done SQL queries but have not done any procedure writing that uses loops so I am at a lost here. I'm using Oracle SQL Developer. Can be done in SQL or PL/SQL
I have a table that resemble this:
Person_ID Score Name Game_ID
1 10 jack 1
1 20 jack 2
2 15 carl 1
2 3 carl 3
4 17 steve 1
How can I loop through this table so that I can grab a players total score for all games played. Result would be like this:
Person_ID Score Name
1 30 jack
2 18 carl
4 17 steve
Also extra credit what If i wanted to just grab say games 1 2?
EDIT: Sorry for not being clear but I do need to do this with a loop even though it can be done without it.
Solution after post edition
This procedure list scores for given game_id. If you omit parameter all games will be summed:
create or replace procedure player_scores(i_game_id number default null) as
begin
for o in (select person_id, name, sum(score) score
from games where game_id = nvl(i_game_id, game_id)
group by person_id, name)
loop
dbms_output.put_line(o.person_id||' '||o.name||' '||o.score);
end loop;
end player_scores;
Previous solution:
You don't need procedure for that, just simple query:
select person_id, name, sum(score)
from your_table
where game_id in (1, 2)
group by person_id, name

Select all rows from SQL based upon existence of multiple rows (sequence numbers)

Let's say I have table data similar to the following:
123456 John Doe 1 Green 2001
234567 Jane Doe 1 Yellow 2001
234567 Jane Doe 2 Red 2001
345678 Jim Doe 1 Red 2001
What I am attempting to do is only isolate the records for Jane Doe based upon the fact that she has more than one row in this table. (More that one sequence number)
I cannot isolate based upon ID, names, colors, years, etc...
The number 1 in the sequence tells me that is the first record and I need to be able to display that record, as well as the number 2 record -- The change record.
If the table is called users, and the fields called ID, fname, lname, seq_no, color, date. How would I write the code to select only records that have more than one row in this table? For Example:
I want the query to display this only based upon the existence of the multiple rows:
234567 Jane Doe 1 Yellow 2001
234567 Jane Doe 2 Red 2001
In PL/SQL
First, to find the IDs for records with multiple rows you would use:
SELECT ID FROM table GROUP BY ID HAVING COUNT(*) > 1
So you could get all the records for all those people with
SELECT * FROM table WHERE ID IN (SELECT ID FROM table GROUP BY ID HAVING COUNT(*) > 1)
If you know that the second sequence ID will always be "2" and that the "2" record will never be deleted, you might find something like:
SELECT * FROM table WHERE ID IN (SELECT ID FROM table WHERE SequenceID = 2)
to be faster, but you better be sure the requirements are guaranteed to be met in your database (and you would want a compound index on (SequenceID, ID)).
Try something like the following. It's a single tablescan, as opposed to 2 like the others.
SELECT * FROM (
SELECT t1.*, COUNT(name) OVER (PARTITION BY name) mycount FROM TABLE t1
)
WHERE mycount >1;
INNER JOIN
JOIN:
SELECT u1.ID, u1.fname, u1.lname, u1.seq_no, u1.color, u1.date
FROM users u1 JOIN users u2 ON (u1.ID = u2.ID and u2.seq_no = 2)
WHERE:
SELECT u1.ID, u1.fname, u1.lname, u1.seq_no, u1.color, u1.date
FROM users u1, thetable u2
WHERE
u1.ID = u2.ID AND
u2.seq_no = 2
Check out the HAVING clause for a summary query. You can specify stuff like
HAVING COUNT(*) >= 2
and so forth.

Resources