Automatically Splitting Rows into Different Worksheets - Run-time error '1004' PasteSpecial method of Range class failed.

dougmarkham

Active Member
Joined
Jul 19, 2016
Messages
252
Office Version
  1. 365
Platform
  1. Windows
Hi folks,

I have been tasked with splitting a master worksheet into multiple worksheets i.e., splitting the data by values in a selected column.
For instance: if the selected column contained different values for 'sales person', the task would be to split sales data for each 'sales person' into a new worksheet (within the same workbook) named after the 'sales person'.

I found some VBA code for splitting into multiple workbooks and modified the code to instead split the data into multiple worksheets. Here is the code:

Code:
[COLOR=#0000cd]Sub[/COLOR] Split()


[COLOR=#0000cd]Dim[/COLOR] example [COLOR=#0000cd]As String[/COLOR]
[COLOR=#0000cd]Dim [/COLOR]data [COLOR=#0000cd]As String[/COLOR]


example = ActiveWorkbook.Name
data = ActiveSheet.Name


vColumn = InputBox("Please indicate which column (i.e. A, B, C, …), you would like to split by", "Column selection")


Columns(vColumn).Copy
Sheets.Add
ActiveSheet.Name = "_Summary"
Range("A1").PasteSpecial
Columns("A").RemoveDuplicates Columns:=1, Header:=xlYes


vCounter = Range("A" & Rows.Count).End(xlUp).Row


[COLOR=#0000cd]For[/COLOR] i = 2 [COLOR=#0000cd]To[/COLOR] vCounter
    vfilter = Sheets("_Summary").Cells(i, 1)
    Sheets(data).Activate
    ActiveSheet.Columns.AutoFilter field:=Columns(vColumn).Column, Criteria1:=vfilter
    Cells.Copy
    ActiveWorkbook.Sheets.Add After:=Worksheets(Worksheets.Count)
   [COLOR=#b22222] Range("A1").PasteSpecial[/COLOR]
   [COLOR=#0000cd] If[/COLOR] vfilter <> "" [COLOR=#0000cd]Then[/COLOR]
        ActiveSheet.Name = vfilter
[COLOR=#0000cd]        Else[/COLOR]
        Application.DisplayAlerts = [COLOR=#0000cd]False[/COLOR]
        ActiveWindow.SelectedSheets.Delete
        Application.DisplayAlerts = [COLOR=#0000cd]True[/COLOR]
[COLOR=#0000cd]    End If[/COLOR]
    'Activate Workbook
    Workbooks(example).Activate
[COLOR=#0000cd]Next i[/COLOR]
Sheets("_Summary").Delete


[COLOR=#0000cd]End Sub[/COLOR]

The idea is that you select the column (e.g., Col C) containing the variable that you're extracting by, then excel selects by the first variable in 'Column C' it comes to, extracts the rows of data with corresponding to that variable, then loops to the next variable down in 'Column C'. Then excel repeats till all the variables in that column have had the data extract completed. So if column C is selected and there are 20 sales persons, it cycles through each sales person.

Using F8 to check each stage in testing, the error occurs after Cells.Copy: specifically when excel tries to paste into the new sheet i.e.,
Code:
    Cells.Copy
    ActiveWorkbook.Sheets.Add After:=Worksheets(Worksheets.Count)
    [COLOR=#ff0000]Range("A1").PasteSpecial[/COLOR]

After pasting, I get the following error messages:
1) Microsoft excel error message - Excel cannot complete this task with available resources. Choose less data or close other applications.
2) VBA error message - Run-time error '1004' PasteSpecial method of Range class failed.

I closed all other applications and shortened the data set but still get the error message.

Now, I looked into this using Google search and one fellow who had a similar experience said:
I don't know if this is any help, but I had a similar problem and this is the note I made to myself relative to that:

Note, doing a WorkBooks…Add after a .Copy apparently clears out the paste buffer,
i.e. the copied data is lost, so attempting a PasteSpecial fails since the buffer is now empty.
Solution: do the .Copy after the .Add
When doing a .Copy / .PasteSpecial, avoid doing anything in between.

Would anybody be willing to help me fix this code if possible, or will anybody suggest an alternative?

Kind regards,

Doug.
 

Excel Facts

Return population for a City
If you have a list of cities in A2:A100, use Data, Geography. Then =A2.Population and copy down.
You just need to note the original worksheet, add the new one, note the name of that, swap back to the first sheet, copy, swap to the new sheet and paste.

Code:
    strSourceSheet = Activesheet.Name
    Cells.Copy
    ActiveWorkbook.Sheets.Add After:=Worksheets(Worksheets.Count)
    strTargetSheet = Activesheet.Name
    strSourceSheet.Activate
    Cells.Copy
    strTargetSheet.Activate
    Range("A1").PasteSpecial
 
Upvote 0
PS, the first error is one that has dogged XL for years. It is caused by all sorts of things you wouldn't expect, for example having sheets at different zoom levels. There's also a notorious security update KB2597166 that can cause issues. Also try deleting everything except personal.xlsb, the XLStart folder or other files you know about from
C:\Users\[username]\AppData\Local\Microsoft\Excel
 
Last edited:
Upvote 0
You just need to note the original worksheet, add the new one, note the name of that, swap back to the first sheet, copy, swap to the new sheet and paste.

Code:
    strSourceSheet = Activesheet.Name
    Cells.Copy
    ActiveWorkbook.Sheets.Add After:=Worksheets(Worksheets.Count)
    strTargetSheet = Activesheet.Name
    strSourceSheet.Activate
    Cells.Copy
    strTargetSheet.Activate
    Range("A1").PasteSpecial

Hi Johnny C,

Thanks for replying!

Just to clarify: I change nothing except replacing

Code:
    ActiveSheet.Columns.AutoFilter field:=Columns(vColumn).Column, Criteria1:=vfilter    
    Cells.Copy
    ActiveWorkbook.Sheets.Add After:=Worksheets(Worksheets.Count)
    [COLOR=#ff0000]Range("A1").PasteSpecial[/COLOR]
with

Code:
    strSourceSheet = Activesheet.Name
    Cells.Copy
    ActiveWorkbook.Sheets.Add After:=Worksheets(Worksheets.Count)
    strTargetSheet = Activesheet.Name
    strSourceSheet.Activate
    Cells.Copy
    strTargetSheet.Activate
    Range("A1").PasteSpecial

?

Kind regards,

Doug
 
Upvote 0
You just need to note the original worksheet, add the new one, note the name of that, swap back to the first sheet, copy, swap to the new sheet and paste.

Code:
    strSourceSheet = Activesheet.Name
    Cells.Copy
    ActiveWorkbook.Sheets.Add After:=Worksheets(Worksheets.Count)
    strTargetSheet = Activesheet.Name
    strSourceSheet.Activate
    Cells.Copy
    strTargetSheet.Activate
    Range("A1").PasteSpecial

Hi Johnny C,

I've inserted your code and used F8 to [FONT=&quot]single step each line. The code[/FONT] seems to function upto: strSourceSheet.Activate, at which point, excel returns a VBA error message: Run-time error '424': Object required. How can this object be defined given that every iteration, excel just adds a number to "Sheet"?

Kind regards,

Doug.

FYI...

Here is the code so far...

Code:
Sub Split()

[COLOR=#0000cd]Dim[/COLOR] example [COLOR=#0000cd]As String[/COLOR]
[COLOR=#0000cd]Dim [/COLOR]data [COLOR=#0000cd]As String[/COLOR]


example = ActiveWorkbook.Name
data = ActiveSheet.Name


vColumn = InputBox("Please indicate which column (i.e. A, B, C, …), you would like to split by", "Column selection")


Columns(vColumn).Copy
Sheets.Add
ActiveSheet.Name = "_Summary"
Range("A1").PasteSpecial
Columns("A").RemoveDuplicates Columns:=1, Header:=xlYes


vCounter = Range("A" & Rows.Count).End(xlUp).Row


[COLOR=#0000cd]For [/COLOR]i = 2 [COLOR=#0000cd]To [/COLOR]vCounter
    vfilter = Sheets("_Summary").Cells(i, 1)
    Worksheets("data").Activate
    ActiveSheet.Columns.AutoFilter field:=Columns(vColumn).Column, Criteria1:=vfilter
    strSourceSheet = ActiveSheet.Name
    Cells.Copy
    ActiveWorkbook.Sheets.Add After:=Worksheets(Worksheets.Count)
    strTargetSheet = ActiveSheet.Name
[COLOR=#ff0000]    strSourceSheet.Activate[/COLOR]
    Cells.Copy
    strTargetSheet.Activate
    Range("A1").PasteSpecial
   [COLOR=#0000cd] If [/COLOR]vfilter <> "" [COLOR=#0000cd]Then[/COLOR]
        ActiveSheet.Name = vfilter
[COLOR=#0000cd]        Else[/COLOR]
        Application.DisplayAlerts = [COLOR=#0000cd]False[/COLOR]
        ActiveWindow.SelectedSheets.Delete
        Application.DisplayAlerts = [COLOR=#0000cd]True[/COLOR]
[COLOR=#0000cd]    End If[/COLOR]
    'Activate Workbook
    Workbooks(example).Activate
[COLOR=#0000cd]Next [/COLOR]i
Sheets("_Summary").Delete


[COLOR=#0000cd]End Sub[/COLOR]
 
Upvote 0
Hello Doug,

In brief, just to clarify:
- You have a Master sheet with sales data for a number of salespeople.
- The names of the salespeople are in Column C of the Master sheet.
- You wish to create a new sheet for each individual salesperson.
- Once the new sheets are created, you wish to transfer all rows of data for each individual to their respective sheet. Hence, if Bob has five rows of sales data then all five rows of his sales data need to be transferred to Bob's new sheet. If Carol has ten rows of sales data then all ten rows of her sales data need to be transferred to Carol's new sheet etc., etc., etc..........

Rows of data in the Master sheet obviously vary but how many columns are used?
Is Column C the actual "name" column?

I assume that row1 in the Master sheet is used for the column headings with data commencing in row2.

If I've understood your query correctly then there are a number of ways that this can be achieved without excessive drain on resource. Please confirm or clarify the above so that we can help sort this out for you.

Cheerio,
vcoolio.
 
Upvote 0
Hello Doug,

In brief, just to clarify:
- You have a Master sheet with sales data for a number of salespeople.
- The names of the salespeople are in Column C of the Master sheet.
- You wish to create a new sheet for each individual salesperson.
- Once the new sheets are created, you wish to transfer all rows of data for each individual to their respective sheet. Hence, if Bob has five rows of sales data then all five rows of his sales data need to be transferred to Bob's new sheet. If Carol has ten rows of sales data then all ten rows of her sales data need to be transferred to Carol's new sheet etc., etc., etc..........

Hi Vcoolio,

The principle is as you suggest except that...
  • I wish to be able to select any column for which to split by value
  • I used the idea of splitting sales people by sales person because it's easy to imagine, and it's an example we may use. However, in my company, this method of splitting data will be reusable for many fields, hence my desire to keep the script less specific.


Rows of data in the Master sheet obviously vary but how many columns are used?
Is Column C the actual "name" column?

No, the current macro creates a selection box where you enter the column designation (A or B or C...etc). It then uses this selection to filter by the values within that column.

The number of columns this macro will be used on will vary. For instance, this weekly task I am currently working---splitting stock reports by supplier---on tends to grow in columns over time due to some fields being supplier specific and because we are gaining more business over time. Ergo, I wish to keep the ability to select the column for which data will be split by. One of the main benefits of this code to us is the fact that the macro just splits by everything in one column without the need to specify the individual values e.g., sales persons - John, Mark, Gabby, Helen etc.

I assume that row1 in the Master sheet is used for the column headings with data commencing in row2.

Yes, that's right in my current project, although I may need to modify the script for other jobs.

Basically, I've already got this macro to work for splitting supplier data into separate workbooks; however, my current project is for the warehouse manager and he wants his data to split into different worksheets within the same workbook. What I'm trying to do is modify the section of the script below in red to open a new worksheet instead of workbook, and populate that with the filtered data.

Code:
Sub SplitNmsm()

Dim nmsm As String
Dim nmss As String


nmsm = ActiveWorkbook.Name
nmss = ActiveSheet.Name


vColumn = InputBox("Please indicate which column (i.e. A, B, C, Â…), you would like to split by", "Column selection")


Columns(vColumn).Copy
Sheets.Add
ActiveSheet.Name = "_Summary"
Range("A1").PasteSpecial
Columns("A").RemoveDuplicates Columns:=1, Header:=xlYes


vCounter = Range("A" & Rows.Count).End(xlUp).Row


For i = 2 To vCounter
    vfilter = Sheets("_Summary").Cells(i, 1)
    Worksheets("nmss").Activate
    ActiveSheet.Columns.AutoFilter field:=Columns(vColumn).Column, Criteria1:=vfilter
    Cells.Copy
[COLOR=#ff0000]    Workbooks.Add[/COLOR]
[COLOR=#ff0000]    Range("A1").PasteSpecial[/COLOR]
[COLOR=#ff0000]            If vfilter <> "" Then[/COLOR]
[COLOR=#ff0000]            ActiveWorkbook.SaveAs ThisWorkbook.Path & "\Non Moving Stock\" & vfilter[/COLOR]
[COLOR=#ff0000]    Else[/COLOR]
[COLOR=#ff0000]            ActiveWorkbook.SaveAs ThisWorkbook.Path & "\Non Moving Stock\_Empty"[/COLOR]
[COLOR=#ff0000]    
    End If[/COLOR]
    ActiveWorkbook.Close
    Workbooks(nmsm).Activate
Next i


Sheets("_Summary").Delete


End Sub

I had originally inserted this code

Code:
    ActiveWorkbook.Sheets.Add After:=Worksheets(Worksheets.Count)
    Range("A1").PasteSpecial
 [COLOR=#0000cd]   If [/COLOR]vfilter <> "" Then
        ActiveSheet.Name = vfilter
        Else
        Application.DisplayAlerts = False
        ActiveWindow.SelectedSheets.Delete
        Application.DisplayAlerts = True
    [COLOR=#0000cd]End If[/COLOR]

However, this error coded after it tried to paste. Johnny suggested a modified revision of this
Code:
strSourceSheet = Activesheet.Name
    Cells.Copy
    ActiveWorkbook.Sheets.Add After:=Worksheets(Worksheets.Count)
    strTargetSheet = Activesheet.Name
   [COLOR=#ff0000] strSourceSheet.Activate[/COLOR]
    Cells.Copy
    strTargetSheet.Activate
    Range("A1").PasteSpecial

...but it failed at: strSourceSheet.Activate.

The error code on this was Run-time error '424': Object required.

Ideally, it would be good to get this to current method to work as it's idea for the business use; however, I am flexible to consider a more efficient approach!
 
Last edited:
Upvote 0
hi Doug
Try:-
Code:
    strSourceSheet = Activesheet.Name
    ActiveWorkbook.Sheets.Add After:=Worksheets(Worksheets.Count)
    strTargetSheet = Activesheet.Name
    Sheets(strSourceSheet).Activate
    Cells.Select
    Selection.Copy
    Sheets(strTargetSheet).Activate
    Range("A1").PasteSpecial
I forgot to put the Sheets around it, silly schoolkid error.

When I work with sheets I make them into objects so I can work on them without worrying what the name is. That's overcomplicating things for your needs.
Here's what I would use
Code:
Dim wksSourceSheet, wksTargetSheet

    Set wksSourceSheet = Activesheet
    ActiveWorkbook.Sheets.Add After:=Worksheets(Worksheets.Count)
    Set wksTargetSheet = Activesheet
    wksSourceSheet.Activate
    Cells.Select
    Selection.Copy
    wksTargetSheet.Activate
    Range("A1").PasteSpecial
What that does, using the Set command, it creates a VBA worksheet object for the source and target sheets. You can then use them as variables. Ditto workbooks. it's more memory intensive but better practice if the name of the sheet might cause problems. For example, if there's a sheet with some information and the user can change the name. it's a bit like Range names where the user can add or remove columns/rows.

Say the sheet was named Control and cell B10 had a value we wanted to use in VBA.
A lot of people would use VBA such as
Code:
intMyNumber = Sheets("Control").Range("B10").Value
The VBA would fail if the user changed the name of the sheet to 'Input' (the code would crash) or inserted or deleted a column and a row above/left of B10 (it would retrieve the wrong cell)
If we select the sheet Control in the project browser and change the name in the properties box to say wksControl and name the cell B10 as 'Input01'. Then if we wanted the value from that cell, even if they changed the name of the sheet and inserted/deleted columns/rows we just need to use
Code:
intMyNumber = wksControl.Range("Input01").Value
and it will still get the right number

it's a lot to take in if you're new to VBA but it's something worth learning to use if other people have the opportunity to monkey around with the workbook.
 
Upvote 0
hi Doug
Try:-
Code:
    strSourceSheet = Activesheet.Name
    ActiveWorkbook.Sheets.Add After:=Worksheets(Worksheets.Count)
    strTargetSheet = Activesheet.Name
    Sheets(strSourceSheet).Activate
    Cells.Select
    Selection.Copy
    Sheets(strTargetSheet).Activate
    Range("A1").PasteSpecial
I forgot to put the Sheets around it, silly schoolkid error.

When I work with sheets I make them into objects so I can work on them without worrying what the name is. That's overcomplicating things for your needs.
Here's what I would use
Code:
Dim wksSourceSheet, wksTargetSheet

    Set wksSourceSheet = Activesheet
    ActiveWorkbook.Sheets.Add After:=Worksheets(Worksheets.Count)
    Set wksTargetSheet = Activesheet
    wksSourceSheet.Activate
    Cells.Select
    Selection.Copy
    wksTargetSheet.Activate
    Range("A1").PasteSpecial
What that does, using the Set command, it creates a VBA worksheet object for the source and target sheets. You can then use them as variables. Ditto workbooks. it's more memory intensive but better practice if the name of the sheet might cause problems. For example, if there's a sheet with some information and the user can change the name. it's a bit like Range names where the user can add or remove columns/rows.

Say the sheet was named Control and cell B10 had a value we wanted to use in VBA.
A lot of people would use VBA such as
Code:
intMyNumber = Sheets("Control").Range("B10").Value
The VBA would fail if the user changed the name of the sheet to 'Input' (the code would crash) or inserted or deleted a column and a row above/left of B10 (it would retrieve the wrong cell)
If we select the sheet Control in the project browser and change the name in the properties box to say wksControl and name the cell B10 as 'Input01'. Then if we wanted the value from that cell, even if they changed the name of the sheet and inserted/deleted columns/rows we just need to use
Code:
intMyNumber = wksControl.Range("Input01").Value
and it will still get the right number

it's a lot to take in if you're new to VBA but it's something worth learning to use if other people have the opportunity to monkey around with the workbook.

Hi Johnny C,

Thanks for explaining this! Let's see if I've got this...
So in my case, if the field to split by in the selected column was sales person---where each 'sales person' get's his own sheet (and before the vba changes the name to the e.g., the 'sales person's' name), more specifically, at the point just before you add a new worksheet---you temporarily define the existing source sheet and what comes after that as the target sheet?

So because it makes them variables, as object, they are then on the hard drive/memory? If I go with your method---viz. Dim wksSourceSheet, wksTargetSheet---I then go to my source sheet (currently sheet 1) and change it's name to wksSourceSheet. I guess I can't set the target sheet the same way because it will be re-added every iteration?

Hope I've got all that?


...Getting back to the issue...


Unfortunately, the paste resulted in the same error codes I initially encountered.

I.e.,
Excel cannot complete this task with available resources. Choose less data or close other applications.
Run-time error '1004': PasteSpecial method of Range class failed
Debug culprit line

It is strange because the same paste function worked when pasting into a new workbook, but it does this when pasting into a new worksheet?

Kind regards,

Doug.

P.S. the error code comes up regardless of whether I use Set wksSourceSheet = Activesheet or strTargetSheet = Activesheet.Name
 
Upvote 0
Hi Doug.

First:
So because it makes them variables, as object, they are then on the hard drive/memory? If I go with your method---viz. Dim wksSourceSheet, wksTargetSheet---I then go to my source sheet (currently sheet 1) and change it's name to wksSourceSheet. I guess I can't set the target sheet the same way because it will be re-added every iteration?

Hope I've got all that?

Yes, you can't set the target the same way, but by reassigning it when you add the new sheet that's ok.
Without getting too technical you could reassign the project object name with VBA but it's unnecessary and involves some technical jiggery pokery.

The worksheet is loaded into memory, so it could cause problems on old PCs with not much RAM or pagefault file and a large complex worksheet.

Second, I noticed at the start you just use
Code:
Range("A1").PasteSpecial

This may be it, when one uses paste special I would expect some parameters. Pastespecial can be a bit finickey too in terms of how you use it so I usually resort to selecting a cell and using selection.pastespecial.

Try this:-
Code:
    Set wksSourceSheet = Activesheet
    ActiveWorkbook.Sheets.Add After:=Worksheets(Worksheets.Count)
    Set wksTargetSheet = Activesheet
    wksSourceSheet.Activate
    Cells.Select
    Selection.Copy
    wksTargetSheet.Activate
    Range("A1").Select
    Selection.PasteSpecial Paste:=xlValues, Operation:=xlNone, SkipBlanks:= False
    Application.CutCopyMode = False
If it doesn't work with
Code:
Range("A1").Select
try
Code:
Cells.Select
 
Last edited:
Upvote 0

Forum statistics

Threads
1,223,228
Messages
6,170,871
Members
452,363
Latest member
merico17

We've detected that you are using an adblocker.

We have a great community of people providing Excel help here, but the hosting costs are enormous. You can help keep this site running by allowing ads on MrExcel.com.
Allow Ads at MrExcel

Which adblocker are you using?

Disable AdBlock

Follow these easy steps to disable AdBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the icon in the browser’s toolbar.
2)Click on the "Pause on this site" option.
Go back

Disable AdBlock Plus

Follow these easy steps to disable AdBlock Plus

1)Click on the icon in the browser’s toolbar.
2)Click on the toggle to disable it for "mrexcel.com".
Go back

Disable uBlock Origin

Follow these easy steps to disable uBlock Origin

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back

Disable uBlock

Follow these easy steps to disable uBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back
Back
Top