为SQL的每一行查找Min,2nd min,3rd min等等

时间:2018-08-01 09:56:32

标签: sql oracle

我遇到这样的情况,我需要根据共同的键属性为每一行分别找到分钟,第二分钟,第三分钟等等。

表1(数量> = 1)

╔═══════════════════╗
║ Item Location Qty ║
╠═══════════════════╣
║ 500    Loc1     5 ║
║ 501    Loc2     2 ║
║ 501    Loc3     1 ║
╚═══════════════════╝

表2(始终为1)

╔══════════════════════════╗
║ Item Location Qty Asset  ║
╠══════════════════════════╣
║ 500    Loc1      1   11  ║
║ 500    Loc1      1   12  ║
║ 500    Loc1      1   13  ║
║ 500    Loc1      1   14  ║
║ 500    Loc1      1   15  ║
║ 500    Loc1      1   10  ║
║ 500    Loc1      1    9  ║
║ 500    Loc1      1    8  ║
║ 500    Loc1      1    7  ║
║ 501    Loc2      1    27 ║
╚══════════════════════════╝

必需的输出-如果表1中的数量为5,则输出应具有5行(即使表2中少于5行)
并且每行应具有min,2nd min,3rd min,4th min和第5分钟资产。

示例输出:

╔══════════════════════════╗
║ Item Location Qty Asset  ║
╠══════════════════════════╣
║ 500    Loc1     1     7  ║
║ 500    Loc1     1     8  ║
║ 500    Loc1     1     9  ║
║ 500    Loc1     1     10 ║
║ 500    Loc1     1     11 ║
║ 501    Loc2     1     27 ║
║ 501    Loc2     1        ║
║ 501    Loc3     1        ║
╚══════════════════════════╝

3 个答案:

答案 0 :(得分:2)

您可以使用分层查询根据table1qty行转换为多行:

select item, location, qty, level as rn
from table1
connect by level <= qty
and item = prior item
and location = prior location
and prior dbms_random.value is not null;

我包含了level as rn,以后可以用作伪密钥。

您可以使用解析函数从table2行中获得等效的键值;我假设您是指分钟,第二分钟等。是指资产应显示的顺序,因此该列用于order by子句:

select t2.*,
  row_number() over (partition by item, location order by asset) as rn
from table2 t2;

然后,如果您同时提供CTE和CTE,则可以外部加入结果:

with t1 as (
  select item, location, qty, level as rn
  from table1
  connect by level <= qty
  and item = prior item
  and location = prior location
  and prior dbms_random.value is not null
),
t2 as (
  select t2.*,
    row_number() over (partition by item, location order by asset) as rn
  from table2 t2
)
select t1.item, t1.location, 1 as qty, t2.asset
from t1
left join t2 on t2.item = t1.item and t2.location = t1.location and t2.rn = t1.rn;

使用项目,位置上面两个子查询中的伪rn值作为合并的跟踪条件。

您的样本数据将得到:

      ITEM LOCATION        QTY      ASSET
---------- -------- ---------- ----------
       500 Loc1              1          7
       500 Loc1              1          8
       500 Loc1              1          9
       500 Loc1              1         10
       500 Loc1              1         11
       501 Loc2              1         27
       501 Loc2              1           
       501 Loc3              1           

8 rows selected. 

答案 1 :(得分:1)

一种略短的方法:

select il.item, il.loc, il.qty, a.asset
from  item_locations il
cross apply ( SELECT rownum rn FROM dual CONNECT BY level <= il.qty ) rn
left outer join lateral 
( SELECT row_Number() over ( order by a.asset) rn, a.asset
  FROM assets a 
  WHERE a.item = il.item and a.loc = il.loc) a ON a.rn = rn.rn;

基本上,rn联接为每个qty值生成一行,然后根据资产编号的排序位置对资产进行外部联接。

带有数据的完整示例:

with item_locations ( item, loc, qty ) AS 
( SELECT 500, 'Loc1', 5 FROM DUAL UNION ALL
  SELECT 501, 'Loc2', 2 FROM DUAL UNION ALL
  SELECT 501, 'Loc3', 1 FROM DUAL ),
assets ( item, loc, qty, asset ) AS (
 SELECT 500,    'Loc1',      1,   11   FROM DUAL UNION ALL
 SELECT 500,    'Loc1',      1,   12   FROM DUAL UNION ALL
 SELECT 500,    'Loc1',      1,   13   FROM DUAL UNION ALL
 SELECT 500,    'Loc1',      1,   14   FROM DUAL UNION ALL
 SELECT 500,    'Loc1',      1,   15   FROM DUAL UNION ALL
 SELECT 500,    'Loc1',      1,   10   FROM DUAL UNION ALL
 SELECT 500,    'Loc1',      1,    9   FROM DUAL UNION ALL
 SELECT 500,    'Loc1',      1,    8   FROM DUAL UNION ALL
 SELECT 500,    'Loc1',      1,    7   FROM DUAL UNION ALL
 SELECT 501,    'Loc2',      1,    27  FROM DUAL )
select il.item, il.loc, il.qty, a.asset
from  item_locations il
cross apply ( SELECT rownum rn FROM dual CONNECT BY level <= il.qty ) rn
left outer join lateral 
( SELECT row_Number() over ( order by a.asset) rn, a.asset
  FROM assets a 
  WHERE a.item = il.item and a.loc = il.loc) a ON a.rn = rn.rn;

结果:

+------+------+-----+-------+
| ITEM | LOC  | QTY | ASSET |
+------+------+-----+-------+
|  500 | Loc1 |   5 |     7 |
|  500 | Loc1 |   5 |     8 |
|  500 | Loc1 |   5 |     9 |
|  500 | Loc1 |   5 |    10 |
|  500 | Loc1 |   5 |    11 |
|  501 | Loc2 |   2 |    27 |
|  501 | Loc2 |   2 |       |
|  501 | Loc3 |   1 |       |
+------+------+-----+-------+

答案 2 :(得分:0)

Alex和Matthew仅使用SQL成功地给出了解决方案。

我认为其他解决方案是创建数据库功能,该功能将管道您需要的所有行:

TYPE tp_r_item_loc_asset IS RECORD
(
    item        yuor_table_2.item%TYPE,
    location    yuor_table_2.location%TYPE,
    qty         yuor_table_2.qty%TYPE,
    asset       yuor_table_2.asset%TYPE
);

TYPE tp_a_item_loc_asset IS TABLE OF tp_r_item_loc_asset;


FUNCTION f_your_pipeline_funtion
    RETURN tp_a_item_loc_asset
    PIPELINED
IS
    v_row      tp_r_item_loc_asset;
    v_asset    NUMBER := null;  
BEGIN

    FOR i IN (SELECT item, location, qty
                FROM your_table_1
               ORDER BY item, location)
    LOOP

        FOR j in 1..i.qty
        LOOP

            BEGIN
            SELECT asset
              INTO v_asset
              FROM yuor_table_2
             WHERE item = i.item
               AND location = i.location
             ORDER BY asset ASC;

            EXCEPTION
                WHEN NO_DATA_FOUND
                THEN
                    v_asset := null;
            END;

            v_row.item      := i.item;
            v_row.location  := i.location;
            v_row.qty       := 1;
            v_row.asset     := v_asset;

        PIPE ROW (v_r_report_blob);

        END LOOP;

    END LOOP;

    RETURN;
EXCEPTION
    WHEN NO_DATA_FOUND
    THEN
        RETURN;
END f_your_pipeline_funtion;

将所有内容放入包装中。

之后,您可以通过以下方式引用(从中选择):

SELECT item, location, qty, asset
  FROM TABLE (p_your_package_name.f_your_pipeline_funtion());

我希望我也能提供帮助!