Insert row + shifting cells in openpyxl - openpyxl

Does openpyxl support the insert row method with "shift cells right/down"?
I was thinking inserting some cells on specific columns. This is to fix dynamic data between the "Header" and "Total" while getting the format of the cells in between the Header and Total. (see Excel Reference).
Tried using insert_row method but it does insert for the entire row/column (correct me if i'm wrong here)
https://openpyxl.readthedocs.io/en/stable/_modules/openpyxl/worksheet/worksheet.html#Worksheet.insert_rows
Excel Reference
Any comments, feedbacks or suggestions will be greatly appreciated! Thank you in advance!!

(Sources:
https://openpyxl.readthedocs.io/en/stable/editing_worksheets.html#moving-ranges-of-cells
https://openpyxl.readthedocs.io/en/stable/_modules/openpyxl/worksheet/worksheet.html#Worksheet.move_range
)
I believe the method that you are looking for is openpyxl.worksheet.worksheet.Worksheet.move_range(). This method allows you shift a range of cells within a worksheet. You can specify either the number of rows to move the range, or the number of columns to move the range, or both. Here is the docstring for the method:
"""
Move a cell range by the number of rows and/or columns:
down if rows > 0 and up if rows < 0
right if cols > 0 and left if cols < 0
Existing cells will be overwritten.
Formulae and references will not be updated.
"""
CAUTION: WHATEVER CONTENT IS IN THE DESTINATION CELLS WILL BE OVERWRITTEN
I have created an example worksheet that is populated by a 9x9 grid to demonstrate.
from openpyxl import Workbook
wb = Workbook()
dest_filename = 'empty_book.xlsx'
ws1 = wb.active
# create a 9x9 grid of numbers
for row in range(1, 10):
ws1.append(range(10))
# move some numbers
ws1.move_range("H5:J9", rows=2, cols=3)
# move some numbers down 1 row
ws1.move_range("A3:B9", rows=1)
wb.save(filename = dest_filename)
Voila! The range H5:J9 has moved down 2 rows and right 3 columns, and the range A3:B9 has moved down 1 row. This is the same result was would have been achieved in normal Excel using Insert>Shift cells down and Insert>Shift cells right.

Related

How to fill cell with data from a separate worksheet in excel?

I am attempting to match 2 columns in two separate worksheets and then fill data from worksheet 2 in worksheet 1.
I need to match Column A(Worksheet 2) to Column D(Worksheet 1). Once Matched I need to fill Column F(Worksheet 1) with the data from Column B(Worksheet 2). Once data is populated I would also like to change the color of Column F(Worksheet 1) based on the data that is present. Worksheet 1
Worksheet 2
Put this in F2 On Sheet 1, update the sheet name Sheet2 to whatever your second sheet is named, then copy down:
=VLOOKUP($D2,Sheet2!$A:$B,2,FALSE)
Then you can apply conditional formatting to Column F on Sheet 1.
If you might have values in Sheet 1 that aren't in Sheet 2, this will handle the error:
=IFERROR(VLOOKUP($D2,Sheet2!$A:$B,2,FALSE),"Not Found!")
[Updated for additional question about spanning accross workbooks]
For another open workbook, use the following and replace [Book2] with the path of the second workbook or the name of an open workbook:
=IFERROR(VLOOKUP($D2,[Book2]Sheet2!$A:$B,2,FALSE),"Not Found!")
Also note, Excel will automatically build all of the references if you select them manually while building the formula in the formula bar: Excel Formulas Overview on MSDN
More information is needed to provide you with an exact code but here is a good start
'Assuming there are 10 rows in each worksheet
dim i as integer
dim j as integer
for i = 1 to 10
for j = 1 to 10
if sheet1.cells(i,4).value = sheet2.cells(j,1).value then
sheet1.cells(i,6).value = sheet1.cells(j,2).value
sheet1.cells(i,6).interior.color = vbyellow
end if
next j
next i
the color can also be controlled with the rgb function, simply replace the vbyellow in the above code:
For example rgb(255,204,255) will be a light pink

how to combine cell vertically in excel

It might be the most silly question in planet. how can I merge two cell values vertically in a repeated manner. as like this:
Column A and B has 400+ cells therefore it is impossible to do what I want to achieve manually.
Note: I want to merge B into A.
You can create a simple loop in VBA that runs through each cell in the data range then adds it to the output column
Sub Merge()
Dim data As Range
Dim cell As Range
Dim output As Range
Dim i As Integer
Set data = Range("A2:B4")
Set output = Range("D2")
i = 0
For Each cell In data
output.Offset(i, 0) = cell
i = i + 1
Next
End Sub
You can use the INDEX function to refer to each cell. If data is in A2:B4, this formula works in any column but must start in row 2 and can then be filled down:
=INDEX($A$2:$B$4,ROW()/2,MOD(ROW(),2)+1)
The formula uses the current row as a counter. On every even row it gets a value from the first column of data and on every odd row it gets a value from the second column of data. After every 2 rows it gets values from the next row of data.

Best way to return data from multiple columns into one row?

I have a sheet with just order numbers and another with order numbers and all of the data associated with those order numbers. I want to match the order numbers and transfer all of the available data into the other sheet. I've been trying to use loops and VLOOKUP but I'm having problems (plus I have 116 columns I want to transfer data from so my vlookup expression doesn't look very nice). Any advice would be appreciated!
this is what I have so far and I'm getting an object error.
I don't think it's the right way to go about it in general though.
Dim LookUpRange As Range
Dim row As Range
Set LookUpRange = Worksheets("batches").Range("B4:B1384")
Set row = Worksheets("batches").Range("C:DL")
For Each row In LookUpRange
row.Select
Selection.FormulaArray ="=VLOOKUP(RC[-1],OrderLvl!RC[-1]:R[1380]C[113],{2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,207,108,109,110,111,112,113,114,115},FALSE)"
Next row
End Sub
Please consider this VBA script to resolve your inquiry:
Sub LookupOuput()
Dim OrderNumberColumn As Range
Set OrderNumberColumn = Worksheets("batches").Range("B2:B1384")
Dim LookUpRange As Range
Set LookUpRange = Worksheets("OrderLvl").Range("C:DL")
Dim cell As Range
Dim FindResult As Range
For Each cell In OrderNumberColumn
If Not cell.Value2 = Empty Then
Set FindResult = LookUpRange.Find(what:=cell.Value2)
If Not FindResult Is Nothing Then
cell.Range("A1:DJ1").Value2 = LookUpRange.Rows(FindResult.row).Value2
End If
End If
Next cell
End Sub
Basically searches for each Order Number in the first sheet on the second sheet. This outputs (if search term exists) the cell that that string is found which we later refer to its row number to output the whole row to the first sheet. Cheers,
A regular VLOOKUP may be able to give you what you need, if you use a small trick...
Insert a row above the data table, and put sequential numbers in
each cell of that row. (ie, A1 = 1, B1 = 2, C1 = 3, etc...)
Do the same thing on your blank table.
Assuming that your first order number is in cell A2, put the following formula into B2: =VLOOKUP($A2,[other sheet name]!$A$1:$DZ$5000,B$1,0)
Drag this formula across all 116 columns, then down all however many rows you've got.
You'll need to adjust the ranges, obviously, but make sure that your lookup array starts in column A. (or alternatively, that your numbers start in the same column as the first column in your array.) Adding the numbers along the top allows you to change what column of the array you're referencing, just by dragging the cell formula.

Excel VBA - selecting the range from first row to the last row

I have a problem with VBA code. I have a sheet with a lot of data around the cells I want. I need to select data in column F, but the position of the first and last cells between the range is to be selected is changing up and down. I created the non empty cells in row X where there is no data do the LastRow function has any refernece but now I dont know how to select the first row
thx for help
If F1 is empty, this selects the first cell with data in the F column
Worksheets("Sheet1").Range("F1").End(xlDown).Select
If F1 may be non-empty you can add a check to see whether it contains text.

Copying Row Info from one sheet to another based on match

I have an excel book that has two sheets: 1) Import 2) Pricing Rules.
Pricing Rules Sheet
The A column is what I need to match on. Example values include STA_PNP4, STA_PST.. and others. There are potentially around 50 different rows in the sheet, and it will continue to grow over time. Then for each row, there are pricing values in columns B to CF.
Import Sheet
This sheet has the same number of columns, but only Column A is filled out. Example values include STA_PNP4_001_00, STA_PNP4_007_00, STA_PST_010_00.. and many more.
What I need to do:
If the text in Import Sheet Column A before the second "_" matches the column identifer in Pricing Rules Sheet Column A, copy the rest of B to CF of Pricing Rules sheet for that row into the Import sheet for the row it matched on.
Any idea on where to begin with this one?
Why don't you do it using formulas only?
Assuming :
1.) Data in Import Sheet is
(col A)
STA_PNP4_007_00
STA_PNP4_001_00
STA_PNP4_001_00
.
.
2.) Data in Pricing Rules Sheet
(Col A) (col B) (ColC) (Col D) .......
STA_PNP4 1 2 3 .....
STA_PST 4 5 6 .....
STA_ASA2 7 8 9 .....
Then write this formula in B1 cell of Import Sheet
=IFERROR(VLOOKUP(LEFT(A1,FIND("",A1,FIND("",A1)+1)-1),PricingRules!$A$1:$CF$100,2,0),"")
Drag it down in column B
and For Column C , D just change index num from 2 to (3 for C) , (4 for D) and like that.
Because it will continue to grow over time you may be best using VBA. However, even with code I would start by applying the ‘groups’ via formula, so as not to have a spreadsheet overburdened with formulae and hence potentially slow and easy to corrupt. Something like part of #xtremeExcel’s solution which I repeat because the underscores have been treated as formatting commands in that answer:
=LEFT(A1,FIND("_",A1,1+FIND("_",A1))-1)
I’d envisage this (copied down) as an additional column in your Import Sheet - to serve as a key field to link to your Pricing Rules Sheet. Say on the extreme left so available for use by VLOOKUP across the entire sheet.
With that as a key field then either:
Write the code to populate Pricing Rules Sheet as frequently as run/desired. Either populating ‘from scratch’ each time (perhaps best for low volumes) or incrementally (likely advisable for high volumes).
Use VLOOKUP (as suggested). However with at least 84 columns and, presumably, many more than 50 rows that is a lot of formulae, though may be viable as a temporary ‘once off’ solution (ie after population Copy/Paste Special/Values).
A compromise. As 2. But preserve a row or a cell with the appropriate formulae/a and copy that to populate the other columns for your additions to your ColumnA and/or ColumnA:B.
Thanks for the input guys.
I got it implemented via a method like this:
{=VLOOKUP(LEFT($A4,7),PricingRules!A3:CF112,{2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84},FALSE)}
That is my ugly function, applied across a whole row, to look up and copy from my pricing rules every column when it finds a match.
Below is the function that I have created for above scenario. Its working as per the requirement that you have mentioned.
Sub CopyData()
Dim wb As Workbook
Dim importws As Worksheet
Dim PricingRulesws As Worksheet
Dim Pricingrowcount As Integer
Dim importRowCount As Integer
Dim FindValue As String
Dim textvalue As String
Dim columncount As Integer
Dim stringarray() As String
'Enter full address of your file ex: "C:\newfolder\datafile.xlsx"
Set wb = Workbooks.Open("C:\newfolder\datafile.xlsx")
'Enter the name of your "import" sheet
Set importws = Sheets("Import")
'Enter the name of your "Pricing" sheet
Set PricingRulesws = Sheets("PricingRules")
For Pricingrowcount = 1 To PricingRulesws.UsedRange.Rows.Count
FindValue = PricingRulesws.Cells(Pricingrowcount, 1)
For importRowCount = 1 To importws.UsedRange.Rows.Count
textvalue = importws.Cells(importRowCount, 1)
stringarray = Split(textvalue, "_")
textvalue = stringarray(0) & "_" & stringarray(1)
If FindValue = textvalue Then
For columncount = 2 To PricingRulesws.UsedRange.Columns.Count
importws.Cells(importRowCount, columncount) = PricingRulesws.Cells(Pricingrowcount, columncount)
Next columncount
End If
Next importRowCount
Next Pricingrowcount
End Sub