Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/oracle/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用pl/sql记录类型显示仓库中产品的平均数量_Sql_Oracle_Plsql - Fatal编程技术网

使用pl/sql记录类型显示仓库中产品的平均数量

使用pl/sql记录类型显示仓库中产品的平均数量,sql,oracle,plsql,Sql,Oracle,Plsql,我需要显示一个产品名称列表,其中ID在100-105之间,所有仓库的平均数量,以及产品数量最多的仓库的名称(对于每个产品)。唯一的问题是平均值(f_avg)不起作用,相反,f_avg显示的是最大数量的产品 输出示例为: 金斯敦HyperX捕食者平均产品:173种,主要分布在旧金山 英特尔至强E5-2687W V4平均产品:90种主要在多伦多 EVGA 12G-P4-3992-KR平均产品:178种主要分布在旧金山 这是我的代码,任何人都知道平均值有什么问题,我也有一个错误: ORA-00979:

我需要显示一个产品名称列表,其中ID在100-105之间,所有仓库的平均数量,以及产品数量最多的仓库的名称(对于每个产品)。唯一的问题是平均值(f_avg)不起作用,相反,f_avg显示的是最大数量的产品

输出示例为:

  • 金斯敦HyperX捕食者平均产品:173种,主要分布在旧金山
  • 英特尔至强E5-2687W V4平均产品:90种主要在多伦多
  • EVGA 12G-P4-3992-KR平均产品:178种主要分布在旧金山
  • 这是我的代码,任何人都知道平均值有什么问题,我也有一个错误:

    ORA-00979:不是第3行表达式ORA-06512:的组

    ORA-06512:在第14行

    ORA-06512:“SYS.DBMS_SQL”,第1721行

    如果你不改变代码的结构会更好,但最重要的是,我需要使用记录类型

     DECLARE
     CURSOR cur_emp_detail IS
       SELECT pproduct_name, avg_quantity, (SELECT w.warehouse_name FROM warehouses w WHERE w.warehouse_id = (SELECT i.warehouse_id FROM inventories i join products p on p.product_id = i.product_id HAVING i.quantity = MAX (i.quantity))) as ware
        FROM (SELECT p.product_name as pproduct_name, AVG (i.quantity) AS avg_quantity
                           FROM products p JOIN inventories i ON p.product_id = i.product_id
                          WHERE (p.product_id BETWEEN 100 AND 105)
                       GROUP BY p.product_name);
     TYPE type_record_type IS RECORD (
       emp_f_name products.product_name%TYPE,
       emp_avg inventories.quantity%type,
       emp_wh warehouses.warehouse_name%type);
     emp_rec_type type_record_type;
         BEGIN
         OPEN cur_emp_detail;
         LOOP
             FETCH cur_emp_detail INTO emp_rec_type;
             EXIT WHEN cur_emp_detail%NOTFOUND;
             dbms_output.Put_line(emp_rec_type.emp_f_name||' average product: '||emp_rec_type.emp_avg||' mostly found in '||emp_rec_type.emp_wh);
         END LOOP;
         CLOSE cur_emp_detail;
     END;
     / 
    

    使用
    批量收集
    比在游标中循环要高效得多。这减少了上下文切换的数量,并且仍然允许您将每一行作为记录类型引用

    DECLARE
        TYPE product_rec IS RECORD
        (
            emp_f_name    products.product_name%TYPE,
            emp_avg       inventories.quantity%TYPE,
            emp_wh        warehouses.warehouse_name%TYPE
        );
    
        TYPE product_t IS TABLE OF product_rec;
    
        l_products   product_t;
    BEGIN
        SELECT product_name, avg_quantity, warehouse_name
          BULK COLLECT INTO l_products
          FROM (SELECT p.product_name,
                       AVG (i.quantity) OVER (PARTITION BY p.product_id)                              AS avg_quantity,
                       w.warehouse_name,
                       ROW_NUMBER ()
                           OVER (PARTITION BY PRODUCT_NAME ORDER BY QUANTITY DESC, WAREHOUSE_NAME)    warehouse_order
                  FROM products  p
                       JOIN inventories i ON p.product_id = i.product_id
                       JOIN warehouses w ON i.warehouse_id = w.warehouse_id
                 WHERE (p.product_id BETWEEN 100 AND 105))
         WHERE warehouse_order = 1;
    
        FOR i IN 1 .. l_products.COUNT
        LOOP
            DBMS_OUTPUT.Put_line (
                   l_products (i).emp_f_name
                || ' average product: '
                || l_products (i).emp_avg
                || ' mostly found in '
                || l_products (i).emp_wh);
        END LOOP;
    END;
    /
    

    使用
    批量收集
    比在游标中循环要高效得多。这减少了上下文切换的数量,并且仍然允许您将每一行作为记录类型引用

    DECLARE
        TYPE product_rec IS RECORD
        (
            emp_f_name    products.product_name%TYPE,
            emp_avg       inventories.quantity%TYPE,
            emp_wh        warehouses.warehouse_name%TYPE
        );
    
        TYPE product_t IS TABLE OF product_rec;
    
        l_products   product_t;
    BEGIN
        SELECT product_name, avg_quantity, warehouse_name
          BULK COLLECT INTO l_products
          FROM (SELECT p.product_name,
                       AVG (i.quantity) OVER (PARTITION BY p.product_id)                              AS avg_quantity,
                       w.warehouse_name,
                       ROW_NUMBER ()
                           OVER (PARTITION BY PRODUCT_NAME ORDER BY QUANTITY DESC, WAREHOUSE_NAME)    warehouse_order
                  FROM products  p
                       JOIN inventories i ON p.product_id = i.product_id
                       JOIN warehouses w ON i.warehouse_id = w.warehouse_id
                 WHERE (p.product_id BETWEEN 100 AND 105))
         WHERE warehouse_order = 1;
    
        FOR i IN 1 .. l_products.COUNT
        LOOP
            DBMS_OUTPUT.Put_line (
                   l_products (i).emp_f_name
                || ' average product: '
                || l_products (i).emp_avg
                || ' mostly found in '
                || l_products (i).emp_wh);
        END LOOP;
    END;
    /
    

    我建议使用如下子查询的结构化方法

    1)生成明细数据的子查询:产品、仓库和数量

    请注意,我假设表
    存货
    有一个主键
    产品标识,仓库标识
    ,如果没有主键,您必须通过分组
    产品标识,仓库标识
    额外聚合数量

    SELECT p.product_name, w.warehouse_name, i.quantity 
     FROM products p 
     JOIN inventories i ON p.product_id = i.product_id
     LEFT OUTER JOIN warehouses w ON w.warehouse_id =  i.warehouse_id
     WHERE (p.product_id BETWEEN 100 AND 105);
     
    PRODUCT_ WAREHOUSE_NAM   QUANTITY
    -------- ------------- ----------
    Kingston San Francisco        173
    EVGA     Toronto              178
    Intel    Toronto               70
    Intel    Toronto               90
    Kingston Toronto              173
    
    2)使用分析函数计算平均数量和仓库等级

    with prd as (
     SELECT p.product_name, w.warehouse_name, i.quantity 
     FROM products p 
     JOIN inventories i ON p.product_id = i.product_id
     LEFT OUTER JOIN warehouses w ON w.warehouse_id =  i.warehouse_id
     WHERE (p.product_id BETWEEN 100 AND 105)
    ),
    prd2 as (
    select 
      PRODUCT_NAME, WAREHOUSE_NAME, QUANTITY,
      avg(QUANTITY) over (partition by PRODUCT_NAME) avg_quantity,
      row_number() over (partition by PRODUCT_NAME order by QUANTITY desc, WAREHOUSE_NAME) warehouse_order
    from prd)
    select * from prd2;
    
    PRODUCT_ WAREHOUSE_NAM   QUANTITY AVG_QUANTITY WAREHOUSE_ORDER
    -------- ------------- ---------- ------------ ---------------
    EVGA     Toronto              178          178               1
    Intel    Toronto               90           80               1
    Intel    Toronto               70           80               2
    Kingston San Francisco        173          173               1
    Kingston Toronto              173          173               2
    
    3)仅获取每个产品的顶级仓库记录

    with prd as (
     SELECT p.product_name, w.warehouse_name, i.quantity 
     FROM products p 
     JOIN inventories i ON p.product_id = i.product_id
     LEFT OUTER JOIN warehouses w ON w.warehouse_id =  i.warehouse_id
     WHERE (p.product_id BETWEEN 100 AND 105)
    ),
    prd2 as (
    select 
      PRODUCT_NAME, WAREHOUSE_NAME, QUANTITY,
      avg(QUANTITY) over (partition by PRODUCT_NAME) avg_quantity,
      row_number() over (partition by PRODUCT_NAME order by QUANTITY desc, WAREHOUSE_NAME) warehouse_order
    from prd)
    select PRODUCT_NAME, WAREHOUSE_NAME, AVG_QUANTITY 
    from prd2
    where warehouse_order = 1; 
    
    PRODUCT_ WAREHOUSE_NAM AVG_QUANTITY
    -------- ------------- ------------
    EVGA     Toronto                178
    Intel    Toronto                 80
    Kingston San Francisco          173
    
    如果您坚持使用游标和记录类型,那么核心逻辑就是上面的查询

    注二:

    使用
    MAX(quantity)
    获得顶级记录是一种幼稚的方法,如果你有联系,那么这种方法会失败,即MAX等于多条记录! 请参阅我的实现,其中,如果是领带,则显示具有较低名称的仓库

     order by QUANTITY desc, WAREHOUSE_NAME 
    
    可以按
    NAME
    s进行分组,但如果有更多同名产品,则分组失败-通常按
    ID
    s进行分组

    样本数据

    create table products as
    select 100 product_id, 'Kingston' product_name from dual union all
    select 101 product_id, 'Intel ' product_name from dual union all
    select 102 product_id, 'EVGA  ' product_name from dual;
    
    create table inventories as
    select 100 product_id, 173 quantity, 1 warehouse_id from dual union all
    select 100 product_id, 173 quantity, 2 warehouse_id from dual union all
    select 101 product_id, 90 quantity, 2 warehouse_id from dual union all
    select 101 product_id, 70 quantity, 2 warehouse_id from dual union all
    select 102 product_id, 178 quantity, 2 warehouse_id from dual;
    
    create table warehouses as
    select 1 warehouse_id, 'San Francisco' warehouse_name from dual union all
    select 2 warehouse_id, 'Toronto' warehouse_name from dual;
    

    我建议使用如下子查询的结构化方法

    1)生成明细数据的子查询:产品、仓库和数量

    请注意,我假设表
    存货
    有一个主键
    产品标识,仓库标识
    ,如果没有主键,您必须通过分组
    产品标识,仓库标识
    额外聚合数量

    SELECT p.product_name, w.warehouse_name, i.quantity 
     FROM products p 
     JOIN inventories i ON p.product_id = i.product_id
     LEFT OUTER JOIN warehouses w ON w.warehouse_id =  i.warehouse_id
     WHERE (p.product_id BETWEEN 100 AND 105);
     
    PRODUCT_ WAREHOUSE_NAM   QUANTITY
    -------- ------------- ----------
    Kingston San Francisco        173
    EVGA     Toronto              178
    Intel    Toronto               70
    Intel    Toronto               90
    Kingston Toronto              173
    
    2)使用分析函数计算平均数量和仓库等级

    with prd as (
     SELECT p.product_name, w.warehouse_name, i.quantity 
     FROM products p 
     JOIN inventories i ON p.product_id = i.product_id
     LEFT OUTER JOIN warehouses w ON w.warehouse_id =  i.warehouse_id
     WHERE (p.product_id BETWEEN 100 AND 105)
    ),
    prd2 as (
    select 
      PRODUCT_NAME, WAREHOUSE_NAME, QUANTITY,
      avg(QUANTITY) over (partition by PRODUCT_NAME) avg_quantity,
      row_number() over (partition by PRODUCT_NAME order by QUANTITY desc, WAREHOUSE_NAME) warehouse_order
    from prd)
    select * from prd2;
    
    PRODUCT_ WAREHOUSE_NAM   QUANTITY AVG_QUANTITY WAREHOUSE_ORDER
    -------- ------------- ---------- ------------ ---------------
    EVGA     Toronto              178          178               1
    Intel    Toronto               90           80               1
    Intel    Toronto               70           80               2
    Kingston San Francisco        173          173               1
    Kingston Toronto              173          173               2
    
    3)仅获取每个产品的顶级仓库记录

    with prd as (
     SELECT p.product_name, w.warehouse_name, i.quantity 
     FROM products p 
     JOIN inventories i ON p.product_id = i.product_id
     LEFT OUTER JOIN warehouses w ON w.warehouse_id =  i.warehouse_id
     WHERE (p.product_id BETWEEN 100 AND 105)
    ),
    prd2 as (
    select 
      PRODUCT_NAME, WAREHOUSE_NAME, QUANTITY,
      avg(QUANTITY) over (partition by PRODUCT_NAME) avg_quantity,
      row_number() over (partition by PRODUCT_NAME order by QUANTITY desc, WAREHOUSE_NAME) warehouse_order
    from prd)
    select PRODUCT_NAME, WAREHOUSE_NAME, AVG_QUANTITY 
    from prd2
    where warehouse_order = 1; 
    
    PRODUCT_ WAREHOUSE_NAM AVG_QUANTITY
    -------- ------------- ------------
    EVGA     Toronto                178
    Intel    Toronto                 80
    Kingston San Francisco          173
    
    如果您坚持使用游标和记录类型,那么核心逻辑就是上面的查询

    注二:

    使用
    MAX(quantity)
    获得顶级记录是一种幼稚的方法,如果你有联系,那么这种方法会失败,即MAX等于多条记录! 请参阅我的实现,其中,如果是领带,则显示具有较低名称的仓库

     order by QUANTITY desc, WAREHOUSE_NAME 
    
    可以按
    NAME
    s进行分组,但如果有更多同名产品,则分组失败-通常按
    ID
    s进行分组

    样本数据

    create table products as
    select 100 product_id, 'Kingston' product_name from dual union all
    select 101 product_id, 'Intel ' product_name from dual union all
    select 102 product_id, 'EVGA  ' product_name from dual;
    
    create table inventories as
    select 100 product_id, 173 quantity, 1 warehouse_id from dual union all
    select 100 product_id, 173 quantity, 2 warehouse_id from dual union all
    select 101 product_id, 90 quantity, 2 warehouse_id from dual union all
    select 101 product_id, 70 quantity, 2 warehouse_id from dual union all
    select 102 product_id, 178 quantity, 2 warehouse_id from dual;
    
    create table warehouses as
    select 1 warehouse_id, 'San Francisco' warehouse_name from dual union all
    select 2 warehouse_id, 'Toronto' warehouse_name from dual;
    

    值得一提的是,大容量收集会消耗更多内存,这取决于您可能遇到错误ORA-04030或ORA-04031的数据量。在这种情况下,您可以考虑使用代码<代码>限制>代码>批量收集到 <代码>批量收集< /代码>增加复杂性,如果您期望的数据集不大,那么正常循环总是更好的。仅选择了~5种产品的信息,因此<10行不应占用太多内存。尽管在子查询中添加了
    GROUP BY i.warehouse\u id
    ,但仍会失败,因为
    ORA-00979:没有GROUP BY表达式
    -
    具有i.quantity=MAX(i.quantity)不允许使用
    ,因为
    i.quantity
    不是
    分组依据
    列。简单的自我测试。谢谢@marmite。我更新了查询以使用类似于您的查询。值得一提的是,批量收集会消耗更多内存,这取决于您可能遇到错误ORA-04030或ORA-04031的数据量。在这种情况下,您可以考虑使用代码<代码>限制>代码>批量收集到 <代码>批量收集< /代码>增加复杂性,如果您期望的数据集不大,那么正常循环总是更好的。仅选择了~5种产品的信息,因此<10行不应占用太多内存。尽管在子查询中添加了
    GROUP BY i.warehouse\u id
    ,但仍会失败,因为
    ORA-00979:没有GROUP BY表达式
    -
    具有i.quantity=MAX(i.quantity)不允许使用
    ,因为
    i.quantity
    不是
    分组依据
    列。简单的自我测试。谢谢@marmite。我更新了查询以使用类似于您的查询。