【问题标题】:oracle query with multiple subqueries具有多个子查询的 oracle 查询
【发布时间】:2009-06-17 13:20:40
【问题描述】:

尝试选择表行,然后使用子查询生成单行列表(item1,item2,item3)

反正sql:

select 
  username,
  concat(firstname || ' ', lastname) as name,
  email,
  phone,
  (
  select 
    ltrim(sys_connect_by_path(res, ', '), ', ')
  from (
    select 
      count(*) over() as cnt, 
      row_number() over(order by ofield) as rnum, 
      (select name from rooms where code=roomcode) as res 
    from adminrooms
    where roomcode=admins.code) /*admins.code - come from main query but it gives error: invalid identifier*/
  where cnt=rnum start with rnum=1 connect by prior rnum=(rnum-1)
  ) as groups
from admins
where frozen=0 and (type <> 'root' or type is null)

问题似乎是表“管理员”中的主要查询字段“代码”在列表生成查询中不起作用

【问题讨论】:

  • 您需要提供更多有关源表(和数据)的详细信息以及您期望的结果。我还会具体说明 Oracle 版本。更高版本实现了“PIVOT”子句将“行”转换为“列”。

标签: oracle


【解决方案1】:

我可以用一个简单的例子重现你的发现。考虑:

SQL> SELECT (SELECT d1.dummy FROM dual d2) d2
  2    FROM dual D1;

D2
--
X

这是可行的,因为子查询“d2”可以看到主查询“d1”的行,但是如果我们添加一个级别,我会遇到与您相同的错误:

SQL> SELECT (SELECT NULL FROM (SELECT d1.dummy FROM dual d3))
  2  FROM dual D1;

SELECT (SELECT NULL FROM (SELECT d1.dummy FROM dual d3))
FROM dual D1                     ~

ORA-00904: "D1"."DUMMY": invalid identifier

这里的子查询“D3”不能看到“D1”中的行的值。

您必须修改您的查询:
* 加入adminadminrooms,然后使用sys_connect_by_path
* 编写一个函数,将代码作为参数并输出您选择的结果。

如果您需要示例,请向我们提供 CREATE TABLE 和示例数据。

【讨论】:

    【解决方案2】:

    根据您的 db 图,最好的方法是使用自定义 string aggregation 函数,然后进行分组。这类似于 mysql group_concat。

    如果你使用上面的链接创建了一个名为 string_agg() 的函数,你可以在你的代码中使用它:

    select a.username, string_agg(c.name) from admins a, adminrooms b, groups c
    where a.code=b.admincode
    and b.groupcode=c.code
    group by a.username
    

    这里是 string_agg 函数创建脚本。只需将其作为脚本运行,您将拥有上面的功能(取自上面显示的链接):

    CREATE OR REPLACE TYPE t_string_agg AS OBJECT
    (
      g_string  VARCHAR2(32767),
    
      STATIC FUNCTION ODCIAggregateInitialize(sctx  IN OUT  t_string_agg)
        RETURN NUMBER,
    
      MEMBER FUNCTION ODCIAggregateIterate(self   IN OUT  t_string_agg,
                                           value  IN      VARCHAR2 )
         RETURN NUMBER,
    
      MEMBER FUNCTION ODCIAggregateTerminate(self         IN   t_string_agg,
                                             returnValue  OUT  VARCHAR2,
                                             flags        IN   NUMBER)
        RETURN NUMBER,
    
      MEMBER FUNCTION ODCIAggregateMerge(self  IN OUT  t_string_agg,
                                         ctx2  IN      t_string_agg)
        RETURN NUMBER
    );
    /
    SHOW ERRORS
    
    
    CREATE OR REPLACE TYPE BODY t_string_agg IS
      STATIC FUNCTION ODCIAggregateInitialize(sctx  IN OUT  t_string_agg)
        RETURN NUMBER IS
      BEGIN
        sctx := t_string_agg(NULL);
        RETURN ODCIConst.Success;
      END;
    
      MEMBER FUNCTION ODCIAggregateIterate(self   IN OUT  t_string_agg,
                                           value  IN      VARCHAR2 )
        RETURN NUMBER IS
      BEGIN
        SELF.g_string := self.g_string || ',' || value;
        RETURN ODCIConst.Success;
      END;
    
      MEMBER FUNCTION ODCIAggregateTerminate(self         IN   t_string_agg,
                                             returnValue  OUT  VARCHAR2,
                                             flags        IN   NUMBER)
        RETURN NUMBER IS
      BEGIN
        returnValue := RTRIM(LTRIM(SELF.g_string, ','), ',');
        RETURN ODCIConst.Success;
      END;
    
      MEMBER FUNCTION ODCIAggregateMerge(self  IN OUT  t_string_agg,
                                         ctx2  IN      t_string_agg)
        RETURN NUMBER IS
      BEGIN
        SELF.g_string := SELF.g_string || ',' || ctx2.g_string;
        RETURN ODCIConst.Success;
      END;
    END;
    /
    SHOW ERRORS
    
    
    CREATE OR REPLACE FUNCTION string_agg (p_input VARCHAR2)
    RETURN VARCHAR2
    PARALLEL_ENABLE AGGREGATE USING t_string_agg;
    /
    SHOW ERRORS
    

    【讨论】:

    • 它工作正常,但我要使用它的数据库没有功能等权限,所以唯一的选择是加入表:(
    【解决方案3】:

    我猜“管理员”表中没有“代码”列……这只是一个小错误。如果有,你就不想加入 adminrooms 的房间代码,而是像“admincode=admins.code”这样的东西。

    【讨论】:

    • 检查了表并验证了列,idd 是一个错字,但现在: admincode=admins.code 给出“admins”。“code”:无效标识符 两个查询单独工作但不能一起工作:(
    【解决方案4】:

    尝试重写你的子查询

       (
        select 
          count(*) over() as cnt, 
          row_number() over(order by ofield) as rnum, 
          (select name from rooms where code=roomcode) as res 
        from adminrooms
        where roomcode=admins.code)
    

    作为主查询中的表

     ... from admins, 
           (
            select 
              roomcode,
              count(*) over() as cnt, 
              row_number() over(order by ofield) as rnum, 
              (select name from rooms where code=roomcode) as res 
            from adminrooms) t
     where t.roomcode = admins.code...
    

    并使用wmsys.WM_CONCAT() 而不是sys_connect_by_path()

    【讨论】:

    • 请注意 wmsys.wm_concat() 是一个未记录的函数。在生产环境中使用它之前,您需要三思而后行。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-22
    相关资源
    最近更新 更多