【问题标题】:Enumerating rows in a inner join枚举内部连接中的行
【发布时间】:2017-01-10 08:27:56
【问题描述】:

我的桌子

id name num
1  a    3
2  b    4

我需要返回每一行 num 次。我是这样做的。

  select DB.BAN_KEY as BAN_KEY, DB.CUST_FULLNAME as CUST_FULLNAME
  from TST_DIM_BAN_SELECTED DB
  inner join (select rownum rn from dual connect by level < 10) a
  on a.rn <= DB.N

生成的表格如下所示。

id  name
1   a
1   a
1   a
2   b
2   b
2   b
2   b

但我还需要将组中的每一行都像这样编号。

id  name row_num
1   a    1
1   a    2
1   a    3
2   b    1
2   b    2
2   b    3
2   b    4

我该怎么做?

【问题讨论】:

    标签: sql oracle join


    【解决方案1】:

    您不需要对虚拟表进行内部连接或分析函数来生成行号;您可以在表本身上使用 connect by(及其相应的级别函数),如下所示:

    WITH tst_dim_ban_selected AS (SELECT 1 ban_key, 'a' cust_fullname, 3 n FROM dual UNION ALL
                                  SELECT 2 ban_key, 'b' cust_fullname, 4 n FROM dual)
    -- end of mimicking your table with data in it. See SQL below
    SELECT db.ban_key,
           db.cust_fullname,
           LEVEL row_num
    FROM   tst_dim_ban_selected db
    CONNECT BY LEVEL <= db.n
               AND PRIOR db.ban_key = db.ban_key -- assuming this is the primary key
               AND PRIOR sys_guid() IS NOT NULL;
    
       BAN_KEY CUST_FULLNAME    ROW_NUM
    ---------- ------------- ----------
             1 a                      1
             1 a                      2
             1 a                      3
             2 b                      1
             2 b                      2
             2 b                      3
             2 b                      4
    

    如果表的主键中有除ban_key 之外的其他列,则需要确保它们包含在connect by 子句的prior &lt;column&gt; = &lt;column&gt;s 列表中。这样 connect by 就可以唯一地识别每一行,这意味着它只在该行上循环,而没有其他行。需要PRIOR sys_guid() IS NOT NULL 以防止发生循环连接。

    【讨论】:

      【解决方案2】:

      您可以为此使用解析函数:

      Select id, name, 
      row_number() over (partition by id, name order by id, name)
      From(/* your query */) t;
      

      这可以在没有子查询的情况下完成:

      Select id, name, 
      row_number() over (partition by id, name order by id, name)
      From /* joins */
      

      【讨论】:

        【解决方案3】:

        你可以用这个:

        SELECT db.ban_key AS ban_key, db.cust_fullname AS cust_fullname,
            ROW_NUMBER() OVER (PARTITION BY db.n ORDER BY db.ban_key) AS row_num
        FROM tst_dim_ban_selected db
        INNER JOIN (SELECT rownum rn FROM dual CONNECT BY level < 10) a
        ON a.rn <= db.n;
        

        【讨论】:

          【解决方案4】:

          使用递归子查询分解子句:

          WITH split ( id, name, rn, n ) AS (
            SELECT BAN_KEY, CUST_FULLNAME, 1, N
            FROM   TST_DIM_BAN_SELECTED
          UNION ALL
            SELECT id, name, rn + 1, n
            FROM   split
            WHERE  rn < n
          )
          SELECT id, name, rn
          FROM   split;
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-09-26
            • 1970-01-01
            • 1970-01-01
            • 2013-09-19
            • 2017-08-16
            • 1970-01-01
            相关资源
            最近更新 更多