2011-11-01 104 views
1

我正在为这个Oracle错误挠头。以下查询完美:Oracle错误 - ORA-00907:缺少右括号

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 

但是,我想按字母顺序返回我的concantonated列表,因为我很挑剔。你以为我会做:

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 

然而,当我尝试这个,我得到的错误:

[Error] Script lines: 15-19 ------------------------ 
ORA-00907: missing right parenthesis 

我可以在自己的SELECT语句运行查询,像这样:

SELECT WM_CONCAT(DISTINCT NAME) 
FROM TPM_TRAININGPLAN JOIN TPM_DELIVERYMETHODS USING (METHODID) 
WHERE PROJECTID=240 
AND VERSIONID=1 
ORDER BY NAME 

它运行良好。我的括号比太阳马戏团队伍更加平衡。为什么错误?

+0

我认为这是行不通的。聚合不受ORDER BY的影响。请测试它,如果需要,我会发布一个用户自定义的聚合函数来排序。不幸的是,我没有支持WM_CONCAT的版本。 – GolezTrol

+0

等你是对的。整个观点是没有意义的,如果我将单独的示例更改为'ORDER BY NAME DESC',那么我会得到相同的结果。我只是假定它的工作原理是因为这些值是按字母顺序排列的。无论如何,我可以用一个简单的LINQ表达式对它们进行排序。 –

+0

[本页]上的LISTAGG示例(http://www.oracle-base.com/articles/misc/StringAggregationTechniques.php)似乎按字母顺序排序,但我对该语法不太熟悉,所以'不是当然,如果这也可以应用于WM_CONCAT。如果不是的话,你总是可以使用LISTAGG,如果这不起作用,我会在今天晚些时候发布一个解决方法。 – GolezTrol

回答

3

我觉得聚集WM_CONCAT功能不受ORDER BY。

因此,如承诺的那样,对结果进行排序的自定义聚合。也可以在早期版本中使用。现在

-- 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; 

您的查询可以是这个样子:

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 
+0

不错的一个!也可能会使用它。 – Benoit

0

尝试

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 

但我认为你应该添加一个WHERE子句用于连接两个表....

+0

奇怪的是,我得到'ORA-00933:SQL命令没有正确结束'的声明 - 我也尝试改变我的嵌套查询使用ANSI风格的连接语法,但同样的错误。 –

+0

在表别名之前摆脱“AS”关键字,我不认为它允许在那里。只是说“方法”,而不是“作为方法”。 – DCookie

+0

是的,我得到了'PLS-306:错误的数字或类型的参数调用'V'' - 这太糟糕了Oracle不能产生任何人类意义上的错误信息。无论如何,无论如何,您无法对聚合子句进行排序。 –