I have two tables, let's call them PERSON and NAME.
PERSON
person_id
dob
NAME
name_id
person_id
name
And let's say that the NAME table has data like:
name_id person_id name
1 1 Joe
2 1 Fred
3 1 Sam
4 2 Jane
5 2 Kim
I need a query (Oracle 10g) that will return
name_id names
1 Joe, Fred, Sam
2 Jane, Kim
Is there a simple way to do this?
Update:
According to the article that figs was kind enough to provide, starting in 9i you can do:
SELECT wmsys.wm_concat(dname) departments FROM dept;
For this example, the answer becomes:
SELECT name_id, wmsys.wm_concat(name) from names group by name_id
The short answer is to use a PL/SQL function. For more details, have a look in this post.
Related
I have a table in oracle that I'm trying to write a query for but having a problem writing it correctly. The data of the table looks like this:
Name
ID
DATE
Shane
1
01JAN2023
Angie
2
02JAN2023
Shane
1
02JAN2023
Austin
3
03JAN2023
Shane
1
03JAN2023
Angie
2
03JAN2023
Tony
4
05JAN2023
What I was trying to come up with was a way to iterate over each day, look at all the records for that day and compare with the rest of the records in the table that came before it and only pull back the first instance of the record based on the ID & Date. The expected output would be:
Name
ID
DATE
Shane
1
01JAN2023
Angie
2
02JAN2023
Austin
3
03JAN2023
Tony
4
05JAN2023
Can anyone tell me what the query should be to accomplish this?
Thank you in advance.
You'll need to convert your date field to a real date so it orders correctly
SELECT name,id,MIN(TO_DATE(date,'DDMONYYYY')) date
FROM table
GROUP BY name,id
Isn't that just
select name, id, min(date_column)
from your_table
group by name, id;
If you don't want to use aggregation, you can use FETCH NEXT ROWS WITH TIES:
SELECT tab.*
FROM tab
ORDER BY ROW_NUMBER() OVER(PARTITION BY Name, Id ORDER BY DATE_)
FETCH NEXT 1 ROWS WITH TIES
Output:
NAME
ID
DATE_
Angie
2
02-JAN-23
Austin
3
03-JAN-23
Shane
1
01-JAN-23
Tony
4
05-JAN-23
Check the demo here.
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.
I have a report that I am trying to write for members that counts the total number of unique values for each type on one line. Here is what I have now:
Member Name Letter Type
John Doe Member 7 Day Letter
Jane Doe Provider 7 Day Letter
Jane Doe Member 7 Day Letter
ID Letter Type
1001 Member 7 Day Letter
1002 Provider 7 Day Letter
How do I get the following output:
Member Name Letter Sent
John Doe 1
Jane Doe 2
This will give you the output you want.
SELECT
"Member Name",
COUNT(DISTINCT "Letter Type") as "Letter Sent"
FROM <your-table>
GROUP BY "Member Name"
Also, I would advise you to go through the Oracle docs or follow some of the tutorials online, if you plan on using Oracle SQL more. These are really basic operations that should be covered by any decent tutorial.
probably you need only count and group by:
SELECT "Member Name"
, "Letter Type"
, COUNT(1) AS n
FROM your_table
GROUP BY "Member Name"
, "Letter Type";
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
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.