I am not very techi-but I have been recording and editing basic Excel Macros for a little while. I have found a few results which almost match my issue, however I am struggling to adapt it so I am hoping someone might be kind enough to help me?!
my issue:
Sheet 1
a/b/c/d
name/black/blue/green
Sam/1//1
Jill//1/
Jill/1//
Sam//1//
Sam/1/1/1
I have a name data base with duplicates in it. I need to de-dupe these, copy just one name (column a) onto a new page, and in the process I don't want to lose some of the data (column b-d) which might be in a duplicate name but not in the one going to be copied over.
Outcome I am hoping for:
Sheet 2
a/b/c/d
name/black/blue/green
Sam/1/1/1
Jill/1/1/
I have quite a few columns to search for data my example is b-d however it is actually AP-EC so it would be helpful if it is obvious which figures I might need to change...?
Thanks in advance.
Kez
You could try ADO, for example:
Dim cn As Object
Dim rs As Object
Dim strFile As String
Dim strCon As String
Dim strSQL As String
Dim strWhere As String
Dim i As Integer
''http://support.microsoft.com/kb/246335
''This saves the name of the active workbook, as this is an example, it is best
''to save before running the code.
strFile = ActiveWorkbook.FullName
''This is a standard connection string for Excel and ADO, it depends on strFile
''being the name of the current workbook, it should be, because that is
''what the first line does
''Note also HDR=Yes, this means that the code expects the first row to be headers,
''in this case, Name, Black, Blue, Green
''You can get more on connection strings from: http://www.connectionstrings.com/
strCon = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & strFile _
& ";Extended Properties=""Excel 8.0;HDR=Yes;IMEX=1"";"
''This creates the objects needed in the code
Set cn = CreateObject("ADODB.Connection")
Set rs = CreateObject("ADODB.Recordset")
''This opens the connection
cn.Open strCon
''This is fairly ordinary SQL, if you are having problems, try a simpler statement
''such as
''SELECT * FROM [Sheet3$]
''It is important that you choose a sheet that exists in the activeworkbook
''and that the sheet has data.
strSQL = "SELECT a.[Name], " _
& "(SELECT Max([Black]) FROM [Sheet3$] b WHERE b.[Name]=a.Name ) As Black, " _
& "(SELECT Max([Blue]) FROM [Sheet3$] b WHERE b.[Name]=a.Name ) As Blue, " _
& "(SELECT Max([Green]) FROM [Sheet3$] b WHERE b.[Name]=a.Name ) As Green " _
& "FROM [Sheet3$] a " _
& "GROUP BY a.[Name]"
''This uses the connection (cn) to open a recordset with the SQL (strSQL)
''3, 3 refers to the cursor and lock type.
''More here: http://www.w3schools.com/ADO/met_rs_open.asp
rs.Open strSQL, cn, 3, 3
''All this does is put headers in sheet of your choice, I chose sheet5.
For i = 0 To rs.fields.Count - 1
Sheets("Sheet5").Cells(1, i + 1) = rs.fields(i).Name
Next
''This copies the recordset into the sheet of your choice,
''Sheet5 again, in this case
Worksheets("Sheet5").Cells(2, 1).CopyFromRecordset rs
Related
I hope someone can give me some direction using the ADODB methods to accomplish my goal.
Brief explanation:
Currently I have code in Outlook VBA that searches an email. If the email passes criteria the Outlook macro opens an Excel workbook, loops through column A to see if an ID number exists. If it does it updates other columns (1 or more columns), if not it creates a new row and writes data into Columns A-C for that row. Then saves and closes the workbook.
I want to speed up the process and the limiting factor is opening the excel workbook (located on a share drive). I have used a simple ADODB macro to read data in another workbook and have seen the speed increases possible. I want to implement that here.
I have been able to establish connection to the workbook from Outlook and place data into a recordset. BUT I don't know how to "loop" through the first column to see if the ID exists yet or not, and further more how to write data into the columns in the workbook (UPDATE SQL command?).
ExcelConnection Code:
Public Sub ExcelConnect(msg As Outlook.MailItem, LType As String)
Dim lngrow As Long
Dim SourceFile As Variant 'used
Dim SourceSheet As String 'used
Dim SourceRange As String 'used
SourceFile = "T:\Capstone Proj\TimeStampsOnlyTest.xlsx"
SourceSheet = "Timestamps"
SourceRange = "A2:F500"
Dim rsCon As Object 'used
Dim rsData As Object 'used
Dim szConnect As String ' used
Dim szSQL As String ' used
Dim lCount As Long
If Val(Application.Version) < 12 Then
szConnect = "Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Data Source=" & SourceFile & ";" & _
"Extended Properties=""Excel 8.0;HDR=Yes"";"
Else
szConnect = "Provider=Microsoft.ACE.OLEDB.12.0;" & _
"Data Source=" & SourceFile & ";" & _
"Extended Properties=""Excel 12.0;HDR=Yes"";"
End If
szSQL = "SELECT * FROM [" & SourceSheet$ & "$" & SourceRange$ & "];"
Set rsCon = CreateObject("ADODB.Connection")
Set rsData = CreateObject("ADODB.Recordset")
rsCon.Open szConnect
rsData.Open szSQL, rsCon, 0, 1, 1
'***Need Help implementing a way to find exisiting ID numbers, or if Exisiting = 0 then INSERT new row into worksheet***'
Select Case LType '// Choose which columns based on Type
Case "MDIQE"
' If columnvalue = 0 Then
' Update column value
Case "MDIQ"
' If columnvalue = 0 Then
' Update column value
'
'........
'
Case "MDIF"
' If columnvalue = 0 Then
' Update column value
'
End Select
'Error handing & success messagebox
End sub
Thank you for the help,
Wagner
In your SELECT statement, include a WHERE clause to search for the ID in column A, something like this:
SELECT COUNT(*) c
FROM [sourceSheet$sourceRange]
WHERE <ColumnAName> = <ID>
note, this is pseudocode, you'll have to properly assemble the statement just like you did when you assigned a string to szSQL
Then check your result set for the value of c, something like this:
If rsData.Fields("c").value = 0 Then
'ID was NOT found, execute SQL INSERT here
Else
'ID was found, execute SQL UPDATE here
End If
i.e., treat your Excel worksheet like a database.
Of course, it would be better if you could use Access as a database (or SQL Server, or Oracle, or ...) since, well, that's what they're designed to do. But I understand that sometimes you've just got to roll with what you've got.
I have had to read in values from an excel file before, but it was a Excel comma separated file. This time I have an excel file with a graph and two tables. I only want to read in the values in one column of a specific table. Here is a picture of the layout of the excel file. I would like to read in the column marked "Amount" in the bottom table marked by a red arrow. I do not want to read in the total of all the amounts below it.
When I was reading in all values from a excel comma separated file I used this code. Initializations and unnecessary logic have been removed to only show the relevent code to this question.
Set objconnection = CreateObject("ADODB.connection")
Set objRecordset = CreateObject("ADODB.recordset")
objconnection.Open "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & strpathtotextfile & ";Extended Properties=""Text;HDR=YES;FMT=Delimited"""
objRecordset.Open "SELECT * FROM [" & ThisFileName & "]", objconnection, adOpenStatic, adLockOptimistic, adCmdText 'select all text lines from the file
Do While Not objRecordset.EOF 'read lines until end of file
'Clear out all the local objects so prior values aren't left there'
SampleName = ""
DateTimeAcquired = ""
Analyte = ""
Concentration = ""
'reads in each value according to column name and save to variable'
SampleName = objRecordset.Fields("Sample Name").Value
DateTimeAcquired = objRecordset.Fields("Date and Time Acquired").Value
Analyte = objRecordset.Fields("Element Full Name").Value
Concentration = objRecordset.Fields("Concentration").Value
'other logic'
objRecordset.MoveNext
Loop
Is there something similar I can do for the excel file I am currently trying to import? Is there a way to only import that one column?
UPDATE: the excel files are always in the same layout as in I am always retrieving information from slots 29G-34G.
You'll need to adjust the file path and sheet name, but something like this should work:
Sub Tester()
Dim cn As New ADODB.Connection
Dim rs As ADODB.Recordset
cn.Open "Provider=Microsoft.ACE.OLEDB.12.0;" & _
"Data Source=C:\Users\thisuser\Desktop\test.xlsx;" & _
"Extended Properties=""Excel 12.0 Xml;HDR=NO"""
Set rs = cn.Execute("select * from [Sheet1$G29:G34]")
Do While Not rs.EOF
Debug.Print rs(0).Value
rs.MoveNext
Loop
End Sub
I have a quick question.
I have an Excel sheet.. which contains descriptions of certain items:For example:
1) Awesome mirror
2) Another Awesome mirror
3) beautiful table
4) Pretty beautiful lovely sofa
5) one more mirror
and so on...
So lets say, I want to place all the mirrors together, all the tables together...
and so on... so basically something which can return me all the instances which contain the word "mirror".
Any ideas on how to solve about this?
You could use a formula solution as below:
=SUM(COUNTIF(A1,"*"&{"table","mirror","sofa"}&"*")*{1,100,1000})
will give
table a score of 1
mirror a score of 100
sofa a score of 1000
allowing an easy numerical sort.
If it was possible that a cell could contain both mirror and sofa then it would get a score of 101. In this case you may either:
be happy to have a separate list of multi-matches
I could further adapt the formula if you can provide how you would like a multi-match handled.
Another possibility is ADO. This will return two rows when an item occurs twice. It would also be possible to play around with another column in ToFind that allowed a Not Like : Like '%' & [ToFind] & '%' And Not Like '%' & [NotToFind] & '%'
Input
Result
Dim cn As Object
Dim rs As Object
Dim strFile As String
Dim strCon As String
Dim strSQL As String
Dim s As String
Dim i As Integer, j As Integer
''This is not the best way to refer to the workbook
''you want, but it is very convenient for notes
''It is probably best to use the name of the workbook.
strFile = ActiveWorkbook.FullName
''Note that if HDR=No, F1,F2 etc are used for column names,
''if HDR=Yes, the names in the first row of the range
''can be used.
''
''This is the Jet 4 connection string, you can get more
''here : http://www.connectionstrings.com/excel
strCon = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & strFile _
& ";Extended Properties=""Excel 8.0;HDR=Yes;IMEX=1"";"
''Late binding, so no reference is needed
Set cn = CreateObject("ADODB.Connection")
Set rs = CreateObject("ADODB.Recordset")
cn.Open strCon
''[ToFind] is a named range, but it does not have to be.
strSQL = "SELECT DISTINCT [List], [ToFind] " _
& "FROM [Sheet1$A:A] a, " _
& "[ToFind] b " _
& "WHERE List Like '%' & [ToFind] & '%'"
rs.Open strSQL, cn, 3, 3
''Pick a suitable empty worksheet for the results
Worksheets("Sheet2").Cells(2, 1).CopyFromRecordset rs
''Tidy up
rs.Close
Set rs = Nothing
cn.Close
Set cn = Nothing
If you just want to show all "Tables" in your list, why not use the Autofilter end type Table in the search field. This way only items with the word "Table" in the string will show up. All other rows will be hidden.
Regards,
Robert
You can create a new column and use this UDF:
Function WhatIsIt(LineItem As Range, AllThings As Range) As String
Dim rv As String, c As Range
Dim v As String, thing As String
v = UCase(LineItem.Cells(1).Value)
rv = ""
If Len(v) > 0 Then
For Each c In AllThings.Cells
thing = c.Value
If Len(thing) > 0 And InStr(v, UCase(thing)) > 0 Then
rv = thing
Exit For
End If
Next c
End If
WhatIsIt = rv
End Function
"AllThings" is a range with a list of what you want to look for. Make sure to put longer terms first: ie. "sofa table" should come before "sofa" or "table".
Note it could use some improvement: it will also return matches when a term is only part of another word in the item description.
I am using excel vba to write a macro that reads data from an Excel sheet and processes it. Basically, I am copying data from an Excel workbook A to a worksheet X in Excel workbook B. Workbook B contains a macro that does this copying and then reads data into a recordset from worksheet X.
I'm running into a real weird issue. My problem is there is one field in the recordset that shows up as blank when I try to print the recordset value.
This is the part of my code that has a problem. packageName is passed into this function that contains a string. The recordset object objRecordset fetches the Name field incorrectly and shows up as blank when I try to print the recordset value for the item, even though it is non-empty. The other fields are printed out just fine. The name field contains letters and numbers like ABC1232WHSJ, ABCD3456. Any idea what is going wrong?
Dim objConnect As ADODB.Connection, objRecordset
Set objConnect = New ADODB.Connection
objConnect.Open "Provider=Microsoft.Jet.OLEDB.4.0;" & "Data Source=" & ActiveWorkbook.Path & "\" & ActiveWorkbook.Name & ";" & "Extended Properties=""Excel 8.0;HDR=Yes;"";"
Const adOpenStatic = 3
Const adLockOptimistic = 3
Const adCmdText = &H1
Set objRecordset = CreateObject("ADODB.Recordset")
objRecordset.Open "Select * FROM [Sheet1$] WHERE Package LIKE '" & _
packageName & "'", objConnect, adOpenStatic, adLockOptimistic, adCmdText
Debug.Print objRecordset.Fields.Item("Package")
Debug.Print objRecordset.Fields.Item("Name")
I've had same problem.
Verify if columns has same number format.
When you use ado connection ado use a format for you first line . if is a number ,for example, and second is string a value in table is empty (if create a table,else you receives a error)
The solution (work's for me) is open workbook before import data ,and format a column with a need format, i use propertie numberformat from range.
[]'s
I'm creating an excel workbook to manage my personal finances. My banks provide transaction data in CSV format and I found a way to import that data into excel using a QueryTable (using a "TEXT" connection.)
I'd like to automatically apply transaction category rules to each imported transaction. I have a worksheet with two columns - a string to match against the transaction "details" provided in my bank's CSV file and the category to apply to the matching transactions.
Is it possible to create an outer join between the CSV data and the categories worksheet and dump the resulting table into another worksheet?
For example (SQL pseudocodeish): SELECT csv.date, csv.details, csv.debit, csv.credit, ws.category FROM [csvfile] csv LEFT OUTER JOIN [worksheet] ws ON csv.details ~= ws.details
~= above would be some kind of string match. I can figure out the SQL, my question is really how to combine the CSV file and worksheet in the same QueryTable.
Excel will open CSV files without blinking, but you can use a connection string, if you prefer. It is even possible to write a query that compares an existing worksheet or named range with a text file using an Excel connection. All you need is a little VBA.
Set cn = CreateObject("ADODB.Connection")
Set rs = CreateObject("ADODB.Recordset")
'Note HDR=Yes, that is, first row contains field names '
'and FMT delimted, ie CSV '
strCon="Provider=Microsoft.Jet.OLEDB.4.0;Data Source=c:\Docs\;" _
& "Extended Properties=""text;HDR=Yes;FMT=Delimited"";"
cn.open strcon
'You would not need delimiters ('') if last field is numeric: '
strSQL="SELECT FieldName1, FieldName2 FROM The.csv " _
& " WHERE LastFieldName='SomeTextValue'"
rs.Open strSQL, cn
Worksheets("Sheet3").Cells(2, 1).CopyFromRecordset rs
You can use any suitable Jet SQL queries against the connection, just be careful about case sensitivity. For example, working with a connection to the current workbook:
Dim cn As Object
Dim rs As Object
Dim strFile As String
Dim strCon As String
Dim strSQL As String
Dim s As String
Dim i As Integer, j As Integer
''This is not the best way to refer to the workbook
''you want, but it is very convenient for notes
''It is probably best to use the name of the workbook.
strFile = ActiveWorkbook.FullName
''Note that if HDR=No, F1,F2 etc are used for column names,
''if HDR=Yes, the names in the first row of the range
''can be used.
''This is the Jet 4 connection string, you can get more
''here : http://www.connectionstrings.com/excel
strCon = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & strFile _
& ";Extended Properties=""Excel 8.0;HDR=Yes;IMEX=1"";"
''Late binding, so no reference is needed
Set cn = CreateObject("ADODB.Connection")
Set rs = CreateObject("ADODB.Recordset")
cn.Open strCon
strSQL = "SELECT * " _
& "FROM [Sheet1$] a " _
& "LEFT JOIN [Text;FMT=Delimited;HDR=Yes;" _
& "DATABASE=C:\Docs].Import.txt b " _
& "ON a.[Id]=b.[Id] "
rs.Open strSQL, cn, 3, 3
''Pick a suitable empty worksheet for the results
Worksheets("Sheet3").Cells(2, 1).CopyFromRecordset rs
''Tidy up
rs.Close
Set rs = Nothing
cn.Close
Set cn = Nothing
It is possible to create an OUTER JOIN referencing disparate data sources (csv, Excel, Access, txt, SQL, Oracle, etc) using ISAM Names in an ADO query. The results are held in a recordset that can be published back to Excel or another datasource as desired. Google "SQL ISAM Names" to find my other posts on the topic.
I am sure a little more info would help clear up my confusion but I don't believe it is possible to set up a SQL query against a CSV as Excel will not recognise it as a Data Source.
Have you thought about simply loading the csv into Excel and generating a pivot table/lookups on the data?