Reputation: 91598
I'm scratching my head over this Oracle error. The following query works perfectly:
SELECT
V.PROJECTID,
(SELECT WM_CONCAT(DISTINCT NAME)
FROM TPM_TRAININGPLAN JOIN TPM_DELIVERYMETHODS USING (METHODID)
WHERE PROJECTID=V.PROJECTID
AND VERSIONID=V.VERSIONID) as Methods
FROM TPM_PROJECTVERSION V
However, I want to return my concantonated list in alphabetical order because I'm picky like that. You'd think I would do:
SELECT
V.PROJECTID,
(SELECT WM_CONCAT(DISTINCT NAME)
FROM TPM_TRAININGPLAN JOIN TPM_DELIVERYMETHODS USING (METHODID)
WHERE PROJECTID=V.PROJECTID
AND VERSIONID=V.VERSIONID ORDER BY NAME) as Methods
FROM TPM_PROJECTVERSION V
However, when I try this I get the error:
[Error] Script lines: 15-19 ------------------------
ORA-00907: missing right parenthesis
I can run the query in its own SELECT statement, like so:
SELECT WM_CONCAT(DISTINCT NAME)
FROM TPM_TRAININGPLAN JOIN TPM_DELIVERYMETHODS USING (METHODID)
WHERE PROJECTID=240
AND VERSIONID=1
ORDER BY NAME
And it runs fine. My parenthesis are more balanced than a Cirque du Soleil troop. Why the error?
Upvotes: 1
Views: 6534
Reputation: 116110
I think the aggregated WM_CONCAT function isn't affected by ORDER BY.
Therefor, as promised, a custom aggregation that sorts the results. Can be used in earlier versions too.
-- A string table type to hold the values to concat. I limited it to 4000 because
-- of trouble with the driver I use. You should be able to change it to 32767, or
-- whatever is VARCHAR2's max size.
CREATE OR REPLACE TYPE TT_STRING as table of varchar2(4000);
-- An aggregate type for the concatenation. It uses the string table to
-- hold all values, and sorts it when you're done aggregating.
CREATE OR REPLACE TYPE AT_CONCATSORTED as object
(
V_ITEMS TT_STRING,
static function ODCIAggregateInitialize(
P_CONTEXT in out AT_CONCATSORTED)
return number,
member function ODCIAggregateIterate(
self in out AT_CONCATSORTED,
P_VALUE in varchar2)
return number,
member function ODCIAggregateTerminate(
self in AT_CONCATSORTED,
P_RESULT out varchar2,
P_FLAGS in number)
return number,
member function ODCIAggregateMerge(
self in out AT_CONCATSORTED,
P_CONTEXT in AT_CONCATSORTED)
return number
);
create or replace type body AT_CONCATSORTED is
static function ODCIAggregateInitialize(
P_CONTEXT in out AT_CONCATSORTED)
return number
is
begin
if P_CONTEXT is null then
P_CONTEXT := AT_CONCATSORTED(TT_STRING(''));
else
P_CONTEXT.V_ITEMS.delete;
end if;
return ODCIConst.Success;
end;
member function ODCIAggregateIterate(
self in out AT_CONCATSORTED,
P_VALUE in varchar2)
return number
is
begin
self.V_ITEMS.extend;
self.V_ITEMS(self.V_ITEMS.last) := P_VALUE;
return ODCIConst.Success;
end;
member function ODCIAggregateTerminate(
self in AT_CONCATSORTED,
P_RESULT out varchar2,
P_FLAGS in number)
return number
is
V_SORTEDITEMS TT_STRING;
begin
select
cast(multiset(select
*
from
table(self.V_ITEMS)
order by
1) as TT_STRING)
into
V_SORTEDITEMS
from
dual;
for i in V_SORTEDITEMS.first..V_SORTEDITEMS.last loop
P_RESULT := P_RESULT || V_SORTEDITEMS(i);
if i < V_SORTEDITEMS.last - 1 then
P_RESULT := P_RESULT || ', ';
end if;
end loop;
return ODCIConst.Success;
end;
member function ODCIAggregateMerge(
self in out AT_CONCATSORTED,
P_CONTEXT in AT_CONCATSORTED)
return number
is
begin
for i in P_CONTEXT.V_ITEMS.first..P_CONTEXT.V_ITEMS.last loop
self.V_ITEMS.extend;
self.V_ITEMS(self.V_ITEMS.last) := P_CONTEXT.V_ITEMS(i);
end loop;
return ODCIConst.Success;
end;
end;
-- The actual concat function
create or replace function CONCATSORTED (input varchar2) return varchar2
aggregate using AT_CONCATSORTED;
Now your query could look something like this:
SELECT
V.PROJECTID,
CONCATSORTED(DISTINCT NAME) as NAMES
FROM
TPM_TRAININGPLAN JOIN TPM_DELIVERYMETHODS USING (METHODID)
WHERE
PROJECTID=V.PROJECTID
AND VERSIONID=V.VERSIONID) as Methods
FROM
TPM_PROJECTVERSION V
Upvotes: 3
Reputation: 6836
try
SELECT
V.PROJECTID,Methods.met
FROM
(SELECT WM_CONCAT(DISTINCT NAME)as met
FROM TPM_TRAININGPLAN JOIN TPM_DELIVERYMETHODS USING (METHODID)
WHERE PROJECTID=V.PROJECTID AND VERSIONID=V.VERSIONID ORDER BY NAME)
as Methods,TPM_PROJECTVERSION V
But I think you should add a WHERE clause for joining the two tables....
Upvotes: 0