a bit of a string matching conundrum in excel-vba - sorting

i'm writing a program at work for a categorizing issue.
i get data in the form of CODE, DESCRIPTION, SUB-TOTAL for example:
LIQ013 COGNAC 25
LIQ023 VODKA 21
FD0001 PRETZELS 10
PP0502 NAPKINS 5
Now it all generally follows something like this...the problem is my company supplies numerous different bars. So there are like 800 records a month with data like this. My boss wants to breakdown the data so she knows how much we spend on a certain category each month. For example:
ALCOHOL 46
FOOD 10
PAPER 5
What I've thought of is I setup a sort of "data-base" which is really a csv text file that contains entries like this:
LIQ,COGNAC,ALCOHOL
LIQ,VODKA,ALCOHOL
FD,PRETZELS,FOOD
FD,POPCORN,FOOD
I've already written code that imports the database as a worksheet and separates each field into its own column. I want excel to look through the file and when it sees LIQ and COGNAC to assign it the ALCOHOL designator. That way I can use a pivot table to get the category sums. For example I want the final product to look like this:
LIQ013 COGNAC 25 ALCOHOL
LIQ023 VODKA 21 ALCOHOL
FD0001 PRETZELS 10 FOOD
PP0502 NAPKINS 5 PAPER
Does anyone have any suggestions? My worry is that a single point expression match to JUST the code i.e. just to LIQ without a match to COGNAC as well would maybe result in problems later when there are conflicting descriptions? I'd also like the user to be able to add ledger entries so that the database of recognized terms grows and becomes more expansive and hopefully more accurate.
EDIT
as per #Marc 's request i'm including my solution:
code file
please note that this is a pretty dumb-ed down solution. i removed a bunch of the fail-safes and other bits of code that were relevant to a robust code but not to our particular solution.
in order to get this to work there are two parts:
the first is the macro source code
the second is the actual file
because all the fail-safes are removed, the file needs to be imported to excel exactly the way it appears. i.e. Sheet1 on the googleDoc should be Sheet1 on the excel, start pasting data at cell "A1". before the macro is run, be sure to select cell "A1" in Sheet1. as i said, there are implementations in the finished product to make it more user friendly! enjoy!
EDIT2
These links suck. They don't paste well into excel.
If your comfortable with it I can email you the actual workbook. Which would help in preserving the formatting etc.

Use a lookup table in a separate sheet. Column A of the lookup sheet contains the lookup value (e.g. PRETZELS), Column B contains the category (FOOD, ALCOHOL, etc). In the cells where you want the category to show up in your original sheet (let's use D3 for the result where B3 holds the "PRETZELS" value), type this formula:
=VLOOKUP(B3,OtherSheet!$A$1:$B$500,2,FALSE)
That assumes that your lookup table is in range A1:B500 of a worksheet named "OtherSheet".
This formula tells Excel to find the lookup value (B3) in column A of your lookup and return the corresponding value from column B of your lookup table. Absolute references (the $) ensure that your formula won't increment cell references when you copy/paste the formula in other cells.
When you get new categories and/or inventory, you can update your lookup table in this one place by just adding new rows to it.

Related

Excel 2017 Formula - Average data by month, while being filterable

I'm not a VBA coder, and I would prefer an excel formula if possible, the easiest solution will be the best one.
Test workbook screenshot
As you can see, I have plenty of columns, which are filterable.
I am attempting to retrieve an average of Column L, but I want the data to be calculated for the correct month in G3:R3.
The resulting calculation needs to be recalculated when filtered, between customers, sites, status, job type etc.
I am referencing the resulting cells in another sheet, which gives an idea of trends I can glance at, as such filtering by month in each sheet, is not an option.
=AVERAGE(IF(MONTH(E9:E1833)=1,(J9:J1833)))
This one does not update with the filtered data.
=SUM(IF(MONTH(E9:E1833)=1,J9:J1833,0)) /SUM(IF(MONTH(E9:E1833)=1,1))
This one does not update with the filtered data.
I have tried 5 different SUBTOTAL formulas, some with OFFSET, none of these produce the same result I get when checking manually.
Each worksheet has over 1,500 hundred rows, the largest is 29148 rows. The data goes back as far as 2005.
Please can someone help me find a solution?
One possible solution is to create a helper column which returns 1 if the row is visible and returns 0 if the row is invisible (or blank). This allows a bit more freedom in your formulas.
For example, if you want to create a helper column in column X, type this into cell X9 and drag down:
= SUBTOTAL(103,A9)
Now you can create a custom average formula, for example:
= SUMPRODUCT((MONTH(E9:E1833)=1)*(X9:X1833)*(J9:J1833))/
SUMPRODUCT((MONTH(E9:E1833)=1)*(X9:X1833))
Not exactly pretty but it gets the job done. (Note this is an array formula, so you must press Ctrl+Shift+Enter on your keyboard instead of just Enter after typing this formula.)
With even more helper columns you could avoid SUMPRODUCT altogether and just accomplish this by doing a single AVERAGEIFS.
For example if you type into cell Y9 and drag down:
= MONTH(E9)
Then your formula could be:
= AVERAGEIFS(J9:J1833,X9:X1833,1,Y9:Y1833,1)
There isn't a clean way to do this without at least one helper function (if you want to avoid VBA).

Separate dated lines into beginning and end of month (LibreOffice)

Given a list of items which have a date as one field, how can I separate one set which have a date in the first few days of the month from those which have a date in the last few days?
The items are gas bills, generally one per month, in a bank statement which relate to each of two separate buildings and need to go into two separate accounts. They were imported from a CSV file.
In practice, the number of lines involved is small, so I've just done it by hand, but the question of how to do it by formula and sort occurred to me, and I neither have nor found an answer.
I hope it is a slightly interesting question.
The function is simply called DAY. You can find it by clicking on the Function Wizard toolbar icon and looking under the Date&Time category.
For example, in cell B1 enter a formula like =DAY(A1) and fill down. Then go to Data -> Sort.

How can I get the values in the Matrix on my SSRS report to repeat?

I know there must be a simple answer to this, but I can't find it.
I have added a couple of textboxes to a Matrix in a BIDS/SSRS report. I've given these textboxes values such as:
=Fields!WEEK1USAGE.Value
It works (after a fashion); when I run the report (either on the Preview tab, or on the Report Server site) I see the first corresponding data value on the report - but only one.
I would think that once a value has been assigned via expressions such as "=Fields!WEEK1USAGE.Value", each value would display (rows would automatically be added).
There must be some property on the Matrix or the textbox that specified this, but I can't see what it might be.
Here is how my report looks (very minimalistic, so far) in the Layout pane:
...and after running, on the Preview tab:
Obviously, I want the report to display as many rows as necessary, not just one. The textboxes do have a "RepeatWith" property, but there description doesn't sound interesting/useful/promising.
I don't see any property on the Matrix control that looks right, either.
I thought maybe the designer was only showing one row of values, and ran the report on the server, too, but there also it just shows the two values.
So what do I need to do to get all the data for a provided field?
Matrices are for display of grouped data and summary information, usually in a horizontally expanding pivot table type of format. Is a matrix really what you are after? Looking at your expression you have =Fields!Week1Usage.Value but in a matrix what I expect to see would be at least =Sum(Fields!Week1Usage.Value) or even better just =Sum(Fields!Usage.Value). Then you would have ProactDescription as your row group and the week as your column group and it would all just work out everything for you, grouping and summing by Proact vertically and expanding the weeks out horizontally.
What seems to be happening is that you have no grouping on rows or columns and no aggregation so it is falling back to the default display which is effectively the First function - it displays the first row of data and as far as the matrix is concerned it has done its job because there is no grouping.
Without knowing your problem or data, I'll make up a scenario that might be what you are doing and discuss how the matrix does the heavy lifting to solve that problem. Let's say you have usage data for multiple Proacts. Each time one is used you record the usage amount and the date and time it is used. It could be used multiple times per day but certainly multiple times in a week. So you might be able to get the times each Proact is used from a table like so:
SELECT ProactDescription, TimeUsed, Usage
FROM ProactUsage
ORDER BY ProactDescription, TimeUsed
In your report you want to show the total weekly usage for each Proact over multiple weeks. Something like this:
Proact Week1 Week2 Week3 ...
Description Usage Usage Usage ...
--------------------------------------------
Anise, Fennel 1 CT 20.00 22.50 16.35 ...
St John's Wort 15.20 33.90 28.25 ...
...
and so on. Using a dataset based on the SQL above we create a matrix and in the row group properties we group on =Fields!ProactDescription.Value and in the column group properties we group on a week expression like =DateDiff(DateInterval.Week, Fields!TimeUsed.Value, Today) and then in the intersection of the row and column we put =Sum(Fields!Usage.Value). To display the header of the column nicely put an expression like
="Week " & DateDiff(DateInterval.Week, Fields!TimeUsed.Value, Today)
The matrix automatically does all the summing by week and product and expands the weeks horizontally for as many as you are reporting. For bonus points you can also put totaling at the end of the columns and the rows to show the total use of that Proact for the period (row total) and total use of all Proacts in that week (column total).

Sort Rows in Excel?

I have an issue with an excel spreadsheet I want to see if I can do without VBA just because it seems easier to implement that way. Basically, there are many columns in the sheet I want to sort. However, I merely want to look at three columns: the title column, the data column and the status column.
In a new spreadsheet, there will be four sections. Each section corresponds to 3 months of the year (ie Jan, Feb, Mar. will map to the first column on the new spreadsheet, April, May, June will map to the second column on the new spreadsheet).
Based on the date, and if the status column has the word "Finished" (in the original spreadsheet), I want to map the title to a certain column under the new spreadsheet based on the date criteria as described in the previous paragraph. So for example, if the original spreadsheet has following:
Title Date Status
Doc1 1/12/13 Finished
Doc2 2/10/13 UnFinished
Doc3 4/1/13 Finished
Doc4 3/31/13 Finished
Would map to, on the new spreadsheet:
1st Column | 2nd Column
Doc1 Doc3
Doc4
I have looked a lot into pivot tables but I can't "automate it" as much as I want to. I have gotten it down to the point where I can change the pivot tables into filtering based on date, but I want it even more automated than that. I've also tried excel formulas but that has been to no avail. Thanks for the help, I really appreciate it!
With a PivotTable it seems fairly easy to 'automate' as far as Sheet 2 as below:
but from there to the result requested is relatively 'manual' without VBA, so may not suit.
For my convenience I have changed the date formats. The PivotTable is constructed as usual/indicated without showing grand totals for rows or for columns (PivotTable Options, Totals & Filters). The Column Labels are Date with Grouping By Quarters with appropriate Starting at: and Ending at: (Group) and Collapse Entire Field (Expand/Collapse).
The formula in I6 is to convert the document count (always 1) to document name:
=IF(F6=1,$E6,"")
However, to allow room for additional quarters in the PivotTable the formula should be moved to the right. The formula would need to be copied across and down as necessary.
The process becomes more ‘manual’ with copying the results of these formulae, pasting them (with Special / Values) into a new location (in the example 2!A1) and, if required, deleting blanks.
This may be against the rules with regards to maintaining the integrity of the OP's request, but hopefully it doesn't offend :)
Here's another option.
Add another column (shame on me, I know) to the original data, and
called this Quarter. The formula that goes next to the existing data
is the following.
=IF(C2="Finished",IF(MONTH(B2)<=3,"Q1",IF(MONTH(B2)<=6,
"Q2",IF(MONTH(B2)<=9,"Q3","Q4"))),C2)
Basically, if the status is "Finished", then determine in what quarter the date is.
Create the pivot table with that data, and then add "Quarter" and
"Title" to the Row Labels (in that order)
Last thing would be to click the arrow next to "Row Labels" and select "Does not Equal" under "Label Filters". There you'll type "Unfinished" (no quotation marks). This will give you something like the image below.
From here the only manual thing you'll need to do is update the data range for the pivot table if more rows are added to the pivot table data and refresh the pivot table if the original data changes
NOTE: To address your question about sorting; after you do the steps above, you can select the Row Labels again and do an A>Z sort to get each quarter to be sorted in alphabetical order

VB6 and data-bound MSHFlexGrid, moving and populating columns

I'm working on a VB6 program that connects to a SQL Server 2008 R2 database. In the past I have always used the MSFlexGrid control and populated it manually. Now, however, the guy who is paying me for this wants me to use data-bound grids instead, which forces me to use the MSHFlexGrid control because I'm using ADO and not DAO. So, I have two questions...
First, how would I move a column in a MSHFlexGrid? For example, if I wanted the third column to appear as the sixth column in the grid, is there a simple single line of code that would do that?
Second, believe it or not, I've never had to do anything in a grid other than display the data, as is, from a recordset. Now, however, I have a recordset with some fields that contain just ID numbers that refer to records in other files - for example, a field containing an ID number referring to a record in the Customers table, instead of the field containing the customer's name. What is the easiest way to, instead of having a column showing customer ID numbers from the recordset, having that column show customer names? I thought I read somewhere that there's a way to embed a sql command in a MSHFlexGrid column, but if there is I wouldn't know how to do it. Is this possible, or is there a simpler way to do it?
TIA,
Kevin
The column order would typically be handled by your SELECT statement.
Say you have a Pies table that has a FruitID foreign key related to the FruitID in a Fruits table:
SELECT PieID AS ID, Pie, Fruit FROM Pies LEFT OUTER JOIN Fruits
ON Pies.FruitID = Fruits.FruitID
This returns 3 items: ID, Pie, and Fruit in that order.
Moving columns after the query/display operation is rarely used, but yes ColPosition can be used for that.
Wow! VB6.... Back to the future! :-)
You can move Columns using the ColPosition Property.
This article shows how you could setup the grid to display hierarchical data.
If you just want to display the customer name on the same line as the main data then that is doable as well by just creating the proper SQL for your data source. For that matter you can control the column order the same way as well.
Now, how about considering upgrading to .Net? Just kidding..... No, I'm not. OK. I am, maybe. :-)

Resources