Reputation: 15876
I have a table that i have to work with which unfortunately is not very well designed. The table lists existing products that have matched to other products. There are two types of matches: a match to a main category product and a match to an alternative category product.
Whenever there is a match, the ID of that match is populated in the relevant column in the table as shown below in PRODUCT_MATCH. So in each product row, there will be a PRODUCT_ID specified in PRODUCT_MAIN_CATEGORY_ID or PRODUCT_ALTERNATIVE_CATEGORY_ID but never both.
PRODUCT
PRODUCT_ID PRODUCT_CATEGORY PRODUCT_SERIAL_NO
1001 Book XSDAD132
1002 MP3 X348023948
1003 DVD 5234234023948
2003 CD SDRX83489
2002 Video 23423879JJ0
PRODUCT_MATCH
PRODUCT_MATCH_ID, PRODUCT_ID, MAIN_CATEGORY_ID, ALTERNATIVE_CATEGORY_ID, PRODUCT_CATEGORY
1 1001 1002 Book
2 1001 1003 Book
3 1002 1004 Book
4 2002 1002 Video
5 2002 1003 Video
6 2002 1001 Video
7 2002 1002 Video
8 1003 2003 DVD
I have to read the PRODUCT_MATCH table so that if there is a match on MAIN_CATEGORY_ID I display the ID, or if there is an ALTERNATIVE_CATEGORY_ID i have to display the product_id and the serial number of the product id.
I have written the following query to display the results
select product_id,
cast(collect(coalesce(MAIN_CATEGORY_ID,
decode(ALTERNATIVE_CATEGORY_ID,null,null, ALTERNATIVE_CATEGORY_ID || '-' || PRODUCT_CATEGORY))) as myType) as product_matches
from product_match
group by product_id
Note: MyType is defined as a table of varchar(2000)
The query will either use MAIN_CATEGORY_ID if it is not null otherwise it will use the value in ALTERNATIVE_CATEGORY_ID to build the output. I want to change this so that it displays the product_id concatenated with the product_serial_no from the PRODUCT number whenever the coalesce function uses the ALTENATIVE_CATEGORY_ID value. This will require a join with the PRODUCT table.
Basically the output I would like to achieve would look like this:
PRODUCT_ID PRODUCT_MATCHES
-----------------------------------
1001 1002,DVD-5234234023948
1002 1004
2002 MP3-X348023948, 1003, 1001, 1002
1003 CD-SDRX83489
I know that i can simply join the tables but it is not as simple as that. The problem is that i only want to use the join if ALTERNATIVE_CATEGORY_ID is used. This means that a simple join will affect the results for when MAIN_CATEGORY_ID is used.
Upvotes: 2
Views: 1058
Reputation: 5792
I think LISTAGG() or WM_CONCAT() functions is what you are looking for as you wrote that you have table not nested table or collection. Collect will return a collection and mostly used with PL/SQL datatypes not with simple tables. The LISTAGG() or WM_CONCAT() will concatenate the values into a single string exactly as in your example. Sorry, I will not add any queries as your output is very confusing to me. I see only Book matches to product_id = 1001, not DVD and other things. It would be nice if you created sample data using SQL Fiddle or simply create tables and insert. Please do this in the future.
This worked for me - the emp_test is exact copy of scott.emp table:
ALTERE TABLE emp_test MODIFY ename VARCHAR2(3000);
Update emp_test set ename = rpad(ename, 3000, ' '); Commit;
SELECT deptno
, LISTAGG(TRIM(SUBSTR(ename, 1, 3000)), ',') WITHIN GROUP (ORDER BY ename) AS employees
, count(*) total_emps
FROM emp_test
GROUP BY deptno
/
SELECT deptno
, WM_CONCAT(TRIM(SUBSTR(ename, 1, 3000))) AS employees
, count(*) total_emps
FROM emp_test
GROUP BY deptno
/
Upvotes: 1
Reputation: 23767
select
pm.product_id,
cast(
collect(
coalesce(
pm.MAIN_CATEGORY_ID,
pm.ALTERNATIVE_CATEGORY_ID || '-' || pr.PRODUCT_SERIAL_NO
)
) as myType
) as product_matches
from
product_match pm
left join PRODUCT pr
on pr.PRODUCT_ID = pm.ALTERNATIVE_CATEGORY_ID
group by
pm.product_id
Upvotes: 4