简体   繁体   中英

SQL Dynamic Self Cross Join using TSql

I have a table that has data like this

Group    Value  
1        A  
1        B  
1        C  
2        F  
2        G  
3        J
3        K

I want to join all members of one group to all members of each of the other groups into a single column like this:

AFJ
AFK
AGJ
AGK
BFJ
BFK
BGJ
BGK
CFJ
CFK
CGJ
CGK

There can be n number of groups and n number of values

Thank you

SQL does not offer many options for such a query. The one standard method is a recursive CTE. Other methods would involve recursive functions or stored procedures.

The following is an example of a recursive CTE that solves this problem:

with groups as (
      select v.*
      from (values (1, 'a'), (1, 'b'), (1, 'c'), (2, 'f'), (2, 'g'), (3, 'h'), (3, 'k')
           ) v(g, val)
     ),
     cte as (
      select 1 as groupid, val, 1 as lev
      from groups
      where g = 1
      union all
      select cte.groupid + 1, cte.val + g.val, lev + 1
      from cte join
           groups g
           on g.g = cte.groupid + 1
     )
select val
from (select cte.*, max(lev) over () as max_lev
      from cte
     ) cte
where lev = max_lev
order by 1;

Some databases that support recursive CTEs don't use the recursive keyword.

Here is a db<>fiddle .

If you need to consider gaps between the groups, ie Group 1, then no 2, then 3.

with t(Grp, val) as (
    select 1,        'A'  from dual
    union all
    select 1,        'B'    from dual
    union all
    select 1,        'C'    from dual
    union all
    select 2,        'F'    from dual
    union all
    select 2,        'G'    from dual
    union all
    select 3,        'J'  from dual
    union all
    select 3,        'K'  from dual
)

, grpIndexes as (
    SELECT ROWNUM indx
         , grp
     FROM (select distinct          
                  grp
             from t)
)

, Grps as (
    select t.*
         , grpIndexes.indx
      from t
     inner join grpIndexes
        on grpIndexes.grp = t.grp
)

, rt(val, indx, lvl) as (
    select val
         , indx
         , 0 as lvl
      from Grps
     where indx = (select min(indx) from Grps)
  union all
    select previous.val || this.val as val
         , this.indx
         , previous.lvl + 1 as lvl
      from rt previous
         , Grps this
     where this.indx = (select min(indx) from Grps where indx > previous.indx)
       and previous.indx <> (select max(indx) from Grps)
)

select val
  from rt
 where lvl = (select max(lvl) from rt)
  order by val
;

Note that I renamed the columns because Group and Value are reserved words.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM