I need to combine one Header Table and six Detail Tables into a single result. To demonstrate I have created a very simple example as follows:
DECLARE @MyHeader TABLE (HeaderPK int, Name varchar(100), Total smallmoney) INSERT INTO @MyHeader (HeaderPK, Name, Total) SELECT 1, 'ABC Company', 1600 DECLARE @MyDetail1 TABLE (Detail1PK int, HeaderFK int, Detail1Description varchar(100), Detail1Amount smallmoney) INSERT INTO @MyDetail1 (Detail1PK, HeaderFK, Detail1Description, Detail1Amount) SELECT 1, 1, 'Detail 1A', 100 UNION SELECT 2, 1, 'Detail 1B', 300 DECLARE @MyDetail2 TABLE (Detail2PK int, HeaderFK int, Detail2Description varchar(100), Detail2AmountA smallmoney, Detail2AmountB smallmoney) INSERT INTO @MyDetail2 (Detail2PK, HeaderFK, Detail2Description, Detail2AmountA, Detail2AmountB) SELECT 1, 1, 'Detail 2A', 100, 100 UNION SELECT 2, 1, 'Detail 2B', 200, 200 UNION SELECT 3, 1, 'Detail 3C', 300, 300 -- Returns 2 Rows, Expected 2 SELECT MyHeader.* ,MyDetail1.* FROM @MyHeader MyHeader FULL JOIN @MyDetail1 MyDetail1 ON MyHeader.HeaderPK = MyDetail1.HeaderFK ORDER BY MyDetail1.Detail1PK -- Returns 6 Rows, Expected 3 SELECT MyHeader.* ,MyDetail1.* ,MyDetail2.* FROM @MyHeader MyHeader FULL JOIN @MyDetail1 MyDetail1 ON MyHeader.HeaderPK = MyDetail1.HeaderFK FULL JOIN @MyDetail2 MyDetail2 ON MyHeader.HeaderPK = MyDetail2.HeaderFK
Notes:
- MSSQL 2008R2
- Each Detail Table will have approximately 0 to 15 records.
In the sample, the Detail Tables have similar structures. In the production system, they are very different.
When you match @MyDetail1 with @MyHeader you get two rows. If you match @MyDetail2 with @MyHeader you will get three rows. However, in your last join you do not tell the system how to match the two rows in @MyDetail1 with the three rows in @MyDetail2 and thus the system assumes you want to match every row of @MyDetail1 with every row of @MyDetail2 resulting 2 x 3 rows or 6 rows.
Solutions:
Each join is performed for each row. So if you join a table with 1 row on a table with matching 2 rows, you get 2 rows. If you join that on a table with 3 rows, you get 6 rows, and so on.
One solution is to execute multiple SQL statements, one for each detail table. The client can move to the next result with the equivalent of
SqlDataReader.NextResult()
.Another option is to
union all
the different statements together; this will result in too many columns, but the rowcount will be reduced.This will give you what you want, based on a slot upwards retrieval of the detail tables. Frankly I am showing this code only because it is mildly interesting. There is normally no good reason to do this type of query.
For transfer efficiency, this would probably be better not to repeat the data in the header columns:
SQL Query
You expand into more detail tables by adding more to the COALSECE, so the 6th detail table would be