Click here to Skip to main content
15,886,110 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I have a table on SQL Server database from which I need to create different tables for each unique value of a particular column.

Here's the depiction of the existing table -
Existing_Table		
Column_1	Column_2	Column_3
A	        XYZ	        Group1
B	        ABC	        Group2
C	        CBA	        Group1
D	        PQR	        Group3
E	        XXX	        Group2
F	        ABC123	        Group1

So the unique values for which I will need to create a new table will be -
UNIQUE Column_3
Group1
Group2
Group3

Now the newly created tables expected to look like-

New_Table_Group1	
Column_1	Column_2
A	        XYZ
C	        CBA
F	        ABC123

New_Table_Group2	
Column_1	Column_2
B	        ABC
E	        XXX

New_Table_Group3	
Column_1	Column_2
D	        PQR


Here the name of the table will be based on the unique value based on which the table is created.

Couldn't achieve this. Can someone please help achieve the expected result? Any help is much appreciated.

What I have tried:

I have tried the below code-

DECLARE @i int 
DECLARE @numrows int
DECLARE @indexcount int
DECLARE @Group varchar(200)
DECLARE @temp_table TABLE (
    idx smallint Primary Key IDENTITY(1,1), Group varchar(200)
    )

-- populate group table
INSERT @temp_table
SELECT distinct Column_3 FROM Existing_Table

-- enumerate the table
SET @i = 1
SET @numrows = (SELECT COUNT(*) FROM @temp_table)
SET @indexcount = (SELECT MAX(idx) FROM @temp_table) 
IF @numrows > 0
    WHILE (@i <= @indexcount)
    BEGIN
      -- get the next Group primary key
        SET @Group = (SELECT Group FROM @temp_table WHERE idx = @i);
        IF OBJECT_ID('dbo.New_Table_@Group', 'U') IS NOT NULL 
            DROP TABLE dbo.New_Table_@Group;
        select Column_1, Column_2  
        into New_Table_@Group
        from Existing_Table where Column_3 = @Group;
        -- increment counter for next Column_3 group value
        SET @i = @i + 1
    END


This fails because this only creates a single new table by name 'New_Table_@Group' itself and doesn't substitute the expected unique value from the intended column and hence doesn't create new table for each unique value of the intended column.
Posted
Updated 26-Jun-18 3:01am
Comments
CHill60 20-Jun-18 6:09am    
Why would you want to do this?
shreessmrv 20-Jun-18 6:22am    
That's a requirement for something that I'm working on. These new tables will be used by different applications for further processing.
CHill60 20-Jun-18 7:50am    
There are at least two better approaches
1. Make the other applications access the original table, OR (better)
2. Create Views that filter the table based on group.

It is very bad practice to create duplicate information like this
shreessmrv 22-Jun-18 2:54am    
Agreed. But this is not feasible in my scenario. the application needs the input in a particular format with predefined set of fields only. The base table has more details hence the application doesn't accept it and thus fails to do the task expected. Only after checking on all these we've come up on this plan of creating different exclusive tables.
CHill60 22-Jun-18 6:34am    
You've just described the exact reason for having views (it also contradicts how you described your problem). Everything you are describing can be achieved using Views without duplicating the data.
To the calling application there should be no apparent distinction between querying a view and querying a table.
If the application doesn't "accept" the results of a query against a table (or a view) then there is a problem with the application. For example it is possibly using "SELECT * FROM ..." - this is very bad practice. List the columns that are required.

You need to use dynamic sql in order to insert the correct group name into the table name(s).
E.g (untested)
SQL
DECLARE @i int 
DECLARE @numrows int
DECLARE @indexcount int
DECLARE @Group varchar(200)
DECLARE @temp_table TABLE (
    idx smallint Primary Key IDENTITY(1,1), [Group] varchar(200)
    )

-- populate group table
INSERT @temp_table
SELECT distinct Column_3 FROM #test		-- sub your table name here

-- enumerate the table
SET @i = 1
SET @numrows = (SELECT COUNT(*) FROM @temp_table)
SET @indexcount = (SELECT MAX(idx) FROM @temp_table) 
IF @numrows > 0
    WHILE (@i <= @indexcount)
    BEGIN
      -- get the next Group primary key
        SET @Group = (SELECT [Group] FROM @temp_table WHERE idx = @i);

		declare @sql nvarchar(max)
		declare @drop nvarchar(max)

		set @drop = 'IF OBJECT_ID(''dbo.New_Table_' + @Group + ''', ''U'') IS NOT NULL DROP TABLE dbo.New_Table_' + @Group
		EXECUTE sp_executesql  @drop

		set @sql = 'SELECT Column_1, Column_2 INTO New_Table_' + @Group + ' FROM #test WHERE Column_3 = ''' + @Group + ''''
		EXECUTE sp_executesql  @sql

        -- increment counter for next Column_3 group value
        SET @i = @i + 1
    END
Also note the use of square brackets around the column name Group in table @temp_table (and everywhere it is used). This is because Group is a reserved word and should not be used as a column name. It can be used as a column name only if surrounded by square brackets - [Group]

[EDIT] For the benefit of other readers, please review my comments to the OP. A better approach would be to create Views to be used by the other application. are describing can be achieved using Views without duplicating the data. To the calling application there should be no apparent distinction between querying a view and querying a table.
The solution provided above could be altered to create views rather than tables, the key is that the sql statements must be dynamic.
 
Share this answer
 
v2
Comments
Maciej Los 25-Jun-18 7:59am    
Well, i prefer "view" solution, which you've already mentioned in the comment to the question.
A5!
CHill60 25-Jun-18 8:04am    
Good point - I will actually update my solution to draw attention to that. Thank you Maciej. Have you gone back to your old username?
Edit - ignore that last bit, it's showing your usual name now! How strange
Maciej Los 25-Jun-18 8:15am    
Strange nick/login behaviour is observed since last CP update... I've read about that in "Bugs and..." forum.
shreessmrv 25-Jun-18 12:49pm    
CHill6, this is creating different tables; but, it is substituting only the first letter of each unique value, like -
if my unique values are AGroup1, AGroup2, BGroup1, CGroup1 then this is creating tables using only the first letter of those unique values, like -
New_Table_A, New_Table_B, New_Table_C (and yes, only one copy for each unique first letter, New_Table_A is the newly created table for the values AGroup1 and AGroup2). Also these tables are empty.
CHill60 25-Jun-18 13:05pm    
You never mentioned using column_1 as part of your table name and my code does not behave as you describe. Improve your question with the code you are actually using and update the requirements with what you are actually trying to do
I got this working with a cursor.

Here's the code that I'm using-
DECLARE @Group varchar(200);
DECLARE @CreateTableScript nvarchar(MAX);

DECLARE groups CURSOR LOCAL FAST_FORWARD FOR
    SELECT
          Column_3 AS [Group]
        , N'IF OBJECT_ID(N''dbo.' + QUOTENAME('New_Table_' + Column_3) + ''', ''U'') IS NOT NULL 
                DROP TABLE dbo.' + QUOTENAME('New_Table_' + Column_3) + ';
            select Column_1, Column_2  
            into dbo.' + QUOTENAME('New_Table_' + Column_3) + '
            from Existing_Table where Column_3 = @Group;' AS CreateTableScript
    FROM (SELECT DISTINCT Column_3 FROM Existing_Table) AS groups;

OPEN groups;
WHILE 1 = 1
BEGIN
    FETCH NEXT FROM groups INTO @Group, @CreateTableScript;
    IF @@FETCH_STATUS = -1 BREAK;
    PRINT @CreateTableScript;
    EXEC sp_executesql
          @CreateTableScript
        , N'@Group varchar(200)'
        , @Group = @Group;
END;
CLOSE groups;
DEALLOCATE groups;
GO


Thanks to @digimanus and @CHill60 for helping out on this that got me learn some good stuff around this.
 
Share this answer
 
Comments
CHill60 27-Jun-18 4:41am    
You were better off using the WHILE loop than a cursor which can lock out the source table. Only ever use cursors as a very last resort.
Either way, given that it was my solution that pointed you to using dynamic sql and EXECUTE sp_executesql, I find it rather rude that you have accepted your own solution, but thank you for including the credit in your solution.
shreessmrv 29-Jun-18 9:12am    
CHill60, Sorry if I sounded rude. That was never my intention. All I wanted was to get this working. Just as it was about the time, I decided to take up what I got working earliest. I'm still open to understand and use the right approach and thereby learn about this. Please let me know how I have to proceed to achieve this using while loop. I'm very much interested to know that and use the same.
CHill60 29-Jun-18 9:33am    
You used a while loop in your original code. The advantage of the while loop over a cursor is that you will not lock the table while you are processing. You will need a unique identifier on your group table (as you already had)

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900