Search code examples
sql-server-2012database-administration

Combine rows from Mulitple tables into single table


I have one parent table Products with multiple child tables -Hoses,Steeltubes,ElectricCables,FiberOptics.

ProductId -Primary key field in Product table ProductId- ForeignKey field in Hoses,Steeltubes,ElectricCables,FiberOptics.

Product table has 1 to many relationship with Child tables

I want to combine result of all tables . For eg - Product P1 has PK field ProductId which is used in all child tables as FK.

If Hoses table has 4 record with ProductId 50 and Steeltubes table has 2 records with ProductId 50 when I perform left join then left join is doing cartesian product of records showing 8 record as result But it should be 4 records .

               ;with HOSESTEELCTE
       as
      (
  select  '' as ModeType, '' as FiberOpticQty , '' as NumberFibers,  '' as    FiberLength,  '' as CableType ,  '' as Conductorsize , '' as Voltage,'' as   ElecticCableLength , s.TubeMaterial , s.TubeQty, s.TubeID , s.WallThickness ,  s.DWP ,s.Length as SteelLength , h.HoseSeries, h.HoseLength ,h.ProductId  
  from Hoses h
   left join
   (
   --'' as HoseSeries,'' as HoseLength ,
  select  TubeMaterial , TubeQty,  TubeID , WallThickness ,  DWP ,        Length,ProductId  from SteelTubes 
   ) s on (s.ProductId = h.ProductId)  

  ) select * from HOSESTEELCTE

Solution

  • Assuming there are no relationships between child tables and you simply want a list of all child entities which make up a product you could generate a cte which has a number of rows which are equal to the largest number of entries across all the child tables for a product. In the example below I have used a dates table to simplify the example. so for this data

    create table products(pid int);  
    insert into products values
    (1),(2);
    create table hoses (pid int,descr varchar(2));
    insert into hoses values (1,'h1'),(1,'h2'),(1,'h3'),(1,'h4');
    create table steeltubes (pid int,descr varchar(2));
    insert into steeltubes values (1,'t1'),(1,'t2');
    create table electriccables(pid int,descr varchar(2));
    truncate table electriccables
    insert into electriccables values (1,'e1'),(1,'e2'),(1,'e3'),(2,'e1');
    

    this cte

        ;with cte as
        (select row_number() over(partition by p.pid order by datekey) rn, p.pid
        from dimdate, products p
        where datekey  < 20050105)
    
    select * from cte
    

    create a cartesian join (one of the rare ocassions where an implicit join helps) pid to rn result

    rn                   pid
    -------------------- -----------
                       1           1
                       2           1
                       3           1
                       4           1
                       1           2
                       2           2
                       3           2
                       4           2
    

    And if we add the child tables

    ;with cte as
    (select row_number() over(partition by p.pid order by datekey) rn, p.pid
    from dimdate, products p
    where datekey  < 20050106)
    select c.pid,h.descr hoses,s.descr steeltubes,e.descr electriccables from cte c
    left join (select h.*, row_number() over(order by h.pid) rn from hoses h) h on h.rn = c.rn and h.pid = c.pid
    left join (select s.*, row_number() over(order by s.pid) rn from steeltubes s) s on s.rn = c.rn and s.pid = c.pid
    left join (select e.*, row_number() over(order by e.pid) rn from electriccables e) e on e.rn = c.rn and e.pid = c.pid
    where h.rn is not null or s.rn is not null or e.rn is not null
    order by c.pid,c.rn
    

    we get this

    pid         hoses steeltubes electriccables
    ----------- ----- ---------- --------------
              1 h1    t1         e1
              1 h2    t2         e2
              1 h3    NULL       e3
              1 h4    NULL       NULL
              2 NULL  NULL       e1