Creating a union using multiple tables

  • I'm a beginner DBA trying to working with a very old application that is using SS2005. Trying to use Reporting services to create automated reports for a database that is poorly designed.

    The database has tables such as

    group_1

    group_2

    group_3

    .

    .

    group_25

    etc..

    Where the application can create and delete tables periodically. I am tasked with managing several databases with varying structures and different numbers of group_? tables. What I have done to resolve this problem is to create a view that unions together all the group_? tables and adds an index column.

    Create View [dbo].[Groups]

    Select '1' AS [Group_Key], * FROM group_1

    UNION ALL

    Select '2' AS [Group_Key], * FROM group_2

    UNION ALL

    Select '3' AS [Group_Key], * FROM group_3

    I can build my reports from this Groups view, however I am creating and altering the view each time a group table is added or removed.

    What I would like is a way of building union view based on the groups that exsist in each database. I have been able to extract the tables using the following:

    SELECT name FROM sys.sysobjects

    WHERE (name LIKE N'group___') or (name LIKE N'group__')

    But I'm not sure how to build the union using this table list with the included index number.

    Appriciate any help,

  • are the group tables all the same structure? If not, then are you stubbing out the fields that don't exist between tables? do all the group tables start with group? Can you supply a script of maybe 3 or 4 tables and layouts?

    For better, quicker answers, click on the following...
    http://www.sqlservercentral.com/articles/Best+Practices/61537/

    For better answers on performance questions, click on the following...
    http://www.sqlservercentral.com/articles/SQLServerCentral/66909/

  • Thanks for the reply. This is my first post, so please forgive the sloppy formating of my post.

    Yes, all tables are of the exact same structure.

    Yes they are all named group_# and incremented sequentially

    group_1

    group_2

    group_3

    .

    .

    group_10

    group_11

    etc..

    I want to combine all fields from all existing group tables into one table/view and add an index number to indicate which group table was the source.

  • This should do it...

    --===== Code to create the view syntax in a variable

    DECLARE @SQL1 VARCHAR(MAX)

    SELECT @SQL1 = 'CREATE VIEW dbo.Groups AS' + CHAR(10)

    + STUFF( -- Gets rid of first UNION ALL

    ( --=== Finds the correct table names and concatenates the

    -- the necessary syntax for each table name to build

    -- view using a "blank" untagged XML Path

    SELECT 'UNION ALL SELECT '

    + SUBSTRING(Name,CHARINDEX('_',Name)+1,256)

    + ' AS Group_Key, * FROM '

    + Name

    + CHAR(10)

    FROM sys.SysObjects

    WHERE Name LIKE 'Group__%' ESCAPE '_'

    FOR XML PATH('')

    )

    ,1,10,'')

    --===== Conditionally drop the view

    IF OBJECT_ID('dbo.Groups','V') IS NOT NULL

    DROP VIEW dbo.Groups

    --===== Create the view using the generated syntax

    EXEC (@SQL1)

    --===== Not required, but show the syntax we just executed

    PRINT @SQL1

    --Jeff Moden


    RBAR is pronounced "ree-bar" and is a "Modenism" for Row-By-Agonizing-Row.
    First step towards the paradigm shift of writing Set Based code:
    ________Stop thinking about what you want to do to a ROW... think, instead, of what you want to do to a COLUMN.

    Change is inevitable... Change for the better is not.


    Helpful Links:
    How to post code problems
    How to Post Performance Problems
    Create a Tally Function (fnTally)

  • I like Jeff's solution, but just wanted to offer an alternative that requires no user input beyond the initial running of the script....(I like not having to think)

    Firstly, here is a database trigger that will alter the view whenever a table is added or dropped

    (sorry the code formatter on here is displaying this wrong - but I have checked the code still works...)

    SET ANSI_NULLS ON

    GO

    SET QUOTED_IDENTIFIER ON

    GO

    /* Create a database trigger that will create/alter the view Groups whenever a group_?? table is created or dropped */

    CREATE TRIGGER dynamic_view_trigger ON DATABASE

    FOR CREATE_TABLE, DROP_TABLE

    AS

    SET ANSI_PADDING ON

    SET CONCAT_NULL_YIELDS_NULL ON

    SET ANSI_WARNINGS ON

    /* Check the table name matches the template we are interested in */

    if EVENTDATA().value('(/EVENT_INSTANCE/ObjectName)[1]','varchar(100)') LIKE 'group\_%' ESCAPE '\'

    exec('

    BEGIN TRY

    DECLARE @sql VARCHAR(MAX)

    SET @sql = ''''

    /*

    *

    * Build up the dynamic SQL for the UNION selects

    * The CASE statement ensures we get UNION in the right place

    * The REPLACE strips out the table number from the name - could use SUBSTRING instead - for the GroupKey column

    *

    */

    SELECT @sql = @sql +

    CASE @sql

    WHEN '''' THEN ''''

    ELSE ''UNION ''

    END +

    ''SELECT ''''''+REPLACE([name],''group_'','''')+'''''' [Group_Key], * FROM ''+[name]+CHAR(13)

    FROM sysobjects WITH(NOLOCK)

    WHERE [name] LIKE ''group\_%'' ESCAPE ''\''

    /* Check if the View already exists - and prepend ALTER/CREATE as appropriate */

    IF OBJECT_ID(''[dbo].[Groups]'') IS NULL

    SET @sql = ''CREATE VIEW [dbo].[Groups] AS ''+@sql

    ELSE

    SET @sql = ''ALTER VIEW [dbo].[Groups] AS ''+@sql

    /* Create the view */

    EXEC(@sql)

    END TRY

    BEGIN CATCH

    /* I just do not want any trigger malfunction to affect the database users */

    END CATCH

    ')

    GO

    SET ANSI_NULLS OFF

    GO

    SET QUOTED_IDENTIFIER OFF

    GO

    ENABLE TRIGGER sample_db_trigger ON DATABASE

    Next some sample sql with which to test it:

    /* No need to leave a mess behind eh? */

    BEGIN TRAN

    /* Create some tables and drop a few rows in */

    CREATE TABLE group_1(col1 INT);

    INSERT group_1 VALUES(1);

    CREATE TABLE group_2(col1 INT);

    INSERT group_2 VALUES(2);

    CREATE TABLE group_3(col1 INT);

    INSERT group_3 VALUES(3);

    INSERT group_3 VALUES(4);

    CREATE TABLE group_4(col1 INT);

    INSERT group_4 VALUES(5);

    CREATE TABLE group_5(col1 INT);

    INSERT group_5 VALUES(6);

    /* Test the view works */

    EXEC('SELECT * FROM Groups');

    /* Drop a table to see if the view copes */

    DROP TABLE group_3;

    EXEC('SELECT * FROM Groups');

    /* clean up */

    ROLLBACK

    Kind of nice, but I expect there could be issues with performance if there were LOTS of group_?? tables. 😀

    MM



    select geometry::STGeomFromWKB(0x0106000000020000000103000000010000000B0000001000000000000840000000000000003DD8CCCCCCCCCC0840000000000000003DD8CCCCCCCCCC08408014AE47E17AFC3F040000000000104000CDCCCCCCCCEC3F9C999999999913408014AE47E17AFC3F9C99999999991340000000000000003D0000000000001440000000000000003D000000000000144000000000000000400400000000001040000000000000F03F100000000000084000000000000000401000000000000840000000000000003D0103000000010000000B000000000000000000143D000000000000003D009E99999999B93F000000000000003D009E99999999B93F8014AE47E17AFC3F400000000000F03F00CDCCCCCCCCEC3FA06666666666FE3F8014AE47E17AFC3FA06666666666FE3F000000000000003D1800000000000040000000000000003D18000000000000400000000000000040400000000000F03F000000000000F03F000000000000143D0000000000000040000000000000143D000000000000003D, 0);

  • Forum Etiquette: How to post Reporting Services problems
  • [/url]
  • Forum Etiquette: How to post data/code on a forum to get the best help - by Jeff Moden
  • [/url]
  • How to Post Performance Problems - by Gail Shaw
  • [/url]

  • I can't help myself, I have to ask, what kind of application is this and why does it create many tables with the exact same schema??

  • Thks mangoo, the trigger is exactly what I was looking for. You guys are the best. This is for a very specialized old application and is not very well designed from a database standpoint, but the company doesn't want to invest in developing a new one at this time. I'll just have to keep trying to deal with it for the time being.

    Thanks again for your help.

  • mister.magoo (11/26/2009)


    ...wanted to offer an alternative that requires no user input beyond the initial running of the script....(I like not having to think)

    How did the ol' Magoo cartoons always end? "Ah, Mister Magoo... you've done it again."

    Nicely done...

    --Jeff Moden


    RBAR is pronounced "ree-bar" and is a "Modenism" for Row-By-Agonizing-Row.
    First step towards the paradigm shift of writing Set Based code:
    ________Stop thinking about what you want to do to a ROW... think, instead, of what you want to do to a COLUMN.

    Change is inevitable... Change for the better is not.


    Helpful Links:
    How to post code problems
    How to Post Performance Problems
    Create a Tally Function (fnTally)

  • Viewing 8 posts - 1 through 7 (of 7 total)

    You must be logged in to reply to this topic. Login to reply