VB.net | Save data from DataGridView to text file (Line per line) - vb.net

The application I designed so far has a DataGridView which loads data from a text file line per line.
All I want is for the code to save the (first row, first column) on the first line as a string, then (first row, second column) on the second line, etc.
Here is an example of what my table looks like:
|-------------------------------------------------------|
| ID | Date | Height | Weight | BMI | Units |
|-------------------------------------------------------|
| 01 | 16/06 | 1.74 | 64 | 20.9 | Metric |
| 02 | 17/06 | 1.74 | 63 | 20.6 | Metric |
|-------------------------------------------------------|
So from this example, after the data has been saved to the text file it should look exactly like this:
01
16/06
1.74
64
20.9
Metric
02
17/06
1.74
63
20.6
Metric
I came across some excellent code which does this with tabs, instead of a next line, here it is:
dgvMeasures.ClipboardCopyMode = DataGridViewClipboardCopyMode.EnableWithoutHeaderText
dgvMeasures.SelectAll()
IO.File.WriteAllText(fileName, dgvMeasures.GetClipboardContent.GetText.TrimEnd)
dgvMeasures.ClearSelection()
NOTE: The DataGridView is called dgvMeasures
Also please note that I cannot provide anything that I have already tried since there is nothing I can do, I have no idea what to do.
So if there is anyone who could help, it would be greatly appreciated

To do this, you just need to use a writer, and go through it in the way you want.
Using writer As New System.IO.StreamWriter(filePath)
For row As Integer = 0 To dgvMeasures.RowCount - 1
For col As Integer = 0 To dgvMeasures.ColumnCount - 1
writer.WriteLine(dgvMeasures.Rows(row).Cells(col).Value.ToString)
Next
Next
End Using
This will go through each column for each row (as you describe), and then go to the next row.
I am sure you have a reason for writing the text file like this, but if you want to read it back in at some point, I would really recommend using a tab-delimited (or similar) format.

Related

how to have one itempointer serialize from 1 to n across the selected rows

as shown in the example below, the output of the query contains blockid startds from 324 and it ends at 127, hence, the itempointer or the row index within the block starts from one for each new block id. in otherwords, as shown below
for the blockid 324 it has only itempointer with index 10
for the blockid 325 it has itempointers starts with 1 and ends with 9
i want to have a single blockid so that the itempointer or the row index starts from 1 and ends with 25
plese let me know how to achive that and
why i have three different blockids?
ex-1
query:
select ctid
from awanti_grid_cell_data agcd
where selectedsiteid = '202230060950'
and centerPointsOfWindowAsGeoJSONInEPSG4326ForCellsInTreatment IS NOT NULL
and centerPointsOfWindowAsGeoJSONInEPSG4326ForCellsInTreatment <> 'None'
result:
|ctid |
|--------|
|(324,10)|
|(325,1) |
|(325,2) |
|(325,3) |
|(325,4) |
|(325,5) |
|(325,6) |
|(325,7) |
|(325,8) |
|(325,9) |
|(326,1) |
|(326,2) |
|(326,3) |
|(326,4) |
|(326,5) |
|(326,6) |
|(326,7) |
|(326,8) |
|(326,9) |
|(327,1) |
|(327,2) |
|(327,3) |
|(327,4) |
|(327,5) |
|(327,6) |
You are missing the point. The ctid is the physical address of a row in the table, and it is none of your business. The database is free to choose whatever place it thinks fit for a table row. As a comparison, you cannot go to the authorities and request that your social security number should be 12345678 - it is simply assigned to you, and you have no say. That's how it is with the physical location of tuples.
Very likely you are not asking this question out of pure curiosity, but because you want to solve some problem. You should instead ask a question about your real problem, and there may be a good answer to that. But whatever problem you are trying to solve, using the ctid is probably not the correct answer, in particular if you want to control it.

Excel VBA Vlookup second most recent data for a value

Currently working on an Excel worksheet with Vlookup. My reference table in Sheet 1 has a list of data along with its date, its name defined as ProjectEntry. For example:
-----------------------------------
| Project No | ID | Service Date |
|------------|----|---------------|
| 01 | A1 | 10/12/17 |
| 02 | B2 | 13/12/17 |
| 01 | A1 | 14/12/17 |
| 03 | C3 | 14/12/17 |
| 01 | A1 | 16/12/17 |
-----------------------------------
Now my Vlookup in Sheet2 wants to lookup the second most recent date based on the ID to get the last service date. For example when I select ID = 01 , Vlookup = 14/12/17.
For the Vlookup formula I managed to get the first entered Service Date (10/12/17):
=VLOOKUP(I7,ProjectEntry[[#All],[ID]:[Service Date]],2,FALSE)
But I'm not sure how to get the 2nd most recent date for A1. What should I add to the formula to make it work?
Instead of seeking the "second-to-last match" we could instead look for the "second highest match", in which case an array formula using the LARGE function will return what you need.
If your example data is arranged in A2:C6 like this:
then you could use this array formula to return the "2nd highest date" where the ID = A1 :
=LARGE(IF($B$2:$B$6="A1",$C$2:$C$6),2)
Your question said you need to look for ID = 01 but those are two different columns. If you instead need to look for `Project No = 01" then your array formula would be :
=LARGE(IF($A$2:$A$6="01",$C$2:$C$6),2)
...that's assuming that Project No is stored as text. If it's actually a number (formatted with a leading zero) then you would use :
=LARGE(IF($A$2:$A$6=1,$C$2:$C$6),2).
☆ Remember that since these are all ARRAY FORMULAS you need to specify that when entering the formulas; instead of using ENTER, finish entering the formula with:
CTRL + SHIFT + ENTER
EDIT:
To clarify whether this method will work, if the data is arranged like this:
...which value should be returned for ID = A1 (or Project No = 1)?
second-to-last (2016-12-17)
second-most-recent? (2014-12-17)

VBA AutoFilter with symbol (*) Not Working

I am trying to filter excel data using AutoFilter, but somehow it is not working.
The data I want to filter represent time and are in format of 00:00 through 23:59.
Specifically, I am trying to filter by the hour, so like "00" through "23", or "00:" through "23:", whichever works.
However, it is not working and none of them gets filtered.
Assuming there is a table like
|ID|Date| time |
| 0 | 7/5 | 00:00|
| 1 | 7/5 | 00:20|
| 2 | 7/5 | 00:35|
| 3 | 7/5 | 00:47|
| 4 | 7/5 | 00:58|
| 5 | 7/5 | 01:03|
| 6 | 7/5 | 01:15|
| 7 | 7/5 | 01:27|
| 8 | 7/5 | 01:48|
I tested the following macro:
Selection.Autofilter Field:=3, Criteria1:="=00*"
hoping that I could get the top 5 rows of the data as their times begin with "00". I looked for information on how to set "start with" in AutoFilter, and I found that star (*) can be used. However, this does not work and none of the rows gets filtered.
Interestingly, if I tried the following:
Selection.Autofilter Field:=3, Criteria1:="00:20"
it worked fine and it filtered the second row only where the time is "00:20".
Why is my first macro with * not working? I tried many different ways to no avail. Can someone tell me why this is not working?
Excel treats time values as decimal numbers. One approach would be is to insert a helper column called "Hour" and put the following formula in D2
=HOUR(C2)
and copy it down.
Now filter the data like below...
Range("$A$1:$D1").Autofilter Field:=4, Criteria1:="=0"

Excel/VBA/Conditional Formatting: Dictionary of Dictionaries

I've got an Excel workbook that obtains data from an MS SQL database. One of the sheets is used to check the data against requirements and to highlight faults. In order to do that, I've got a requirements sheet where the requirement is in a named range; after updating the data I copy the conditional formatting of the table header to all data rows. That works pretty nicely so far. The problem comes when I have more than one set of requirements:
An (agreeably silly) example could be car racing, where requirements may exist for driver's license and min/max horsepower. When looking at the example, please imagine there are a few thousand rows and 71 columns presently...
+-----+--------+----------------+------------+---------+
| Car | Race | RequirementSet | Horsepower | License |
+-----+--------+----------------+------------+---------+
| 1 | Monaco | 2 | 200 | A |
+-----+--------+----------------+------------+---------+
| 2 | Monaco | 2 | 400 | B |
+-----+--------+----------------+------------+---------+
| 3 | Japan | 3 | 200 | C |
+-----+--------+----------------+------------+---------+
| 4 | Japan | 3 | 300 | A |
+-----+--------+----------------+------------+---------+
| 5 | Japan | 3 | 350 | B |
+-----+--------+----------------+------------+---------+
| 6 | Mexico | 1 | 200 | A |
+-----+--------+----------------+------------+---------+
The individual data now needs to be checked against the requirements set in another sheet:
+-------------+---------------+---------------+---------+
| Requirement | MinHorsepower | MaxHorsepower | License |
+-------------+---------------+---------------+---------+
| 1 | 200 | 250 | A |
+-------------+---------------+---------------+---------+
| 2 | 250 | 500 | B |
+-------------+---------------+---------------+---------+
| 3 | 250 | 400 | A |
+-------------+---------------+---------------+---------+
In order to relate back to my present situation, I am only looking at either the Monaco, Japan or Mexico Race, and there is only 1 record in the requirements sheet, where the value in e.g. Cell B2 is always the MinHorsepower and the value in C2 is always the MaxHorsepower. So these cells are a named range that I can access in my data sheet.
Now however I would like to obtain all races at once, and refer conditional formatting formulas to the particular requirement.
Focussing on "Horsepower" in Monaco (requirement set 2), I can now find out that the min Horsepower is 250 and the max is 500 - so I will colour that column for car 1 as red and for car 2 as green.
The formula is programatically copied from the header row (the first conditional format rule is if row(D1) = 1 then do nothing)
I can't decide what the best approach to the problem is. Ideally, the formula is readable, something like `AND(D2 >= MinHorsepower; D2 <= MaxHorsepower) - I cannot imagine it to be maintainable if I had to use Vlookup combined with Indirect and Match to match a column header in requirements for that particular requirement - especially when it comes to combining criteria like in the HP example with min and max above.
I am wondering if I should read the requirements table into a dictionary or something in VBA, and then use a function like
public function check(requirementId as int, requirement$)
which then in Excel I could use like =D2 >= check(c2, "MinHorsepower")
Playing around with this a little bit it appears to be pretty slow as opposed to the previous system where I could only have one requirement. It would be fantastic if you could help me out with a fresh approach to this problem. I'll update this question as I go along; I'm not sure if I managed to illustrate the example really well but the actual data wouldn't mean anything to you.
In any case, thanks for hanging in until here!
Edit 29 October 2016
I have found a solution as basis for mine. Using the following code I can add my whole requirements table to a dictionary, and access the requirement.
Using a class clsRangeToDictionary (based on Tim Williams clsMatrix)
Option Explicit
Private m_array As Variant
Private dictRows As Object
Private dictColumns As Object
Public Sub Init(vArray As Variant)
Dim i As Long
Set dictRows = CreateObject("Scripting.Dictionary")
Set dictColumns = CreateObject("Scripting.Dictionary")
'add the row keys and positions. Skip the first row as it contains the column key
For i = LBound(vArray, 1) + 1 To UBound(vArray, 1)
dictRows.Add vArray(i, 1), i
Next i
'add the column keys and positions, skipping the first column
For i = LBound(vArray, 2) + 1 To UBound(vArray, 2)
dictColumns.Add vArray(1, i), i
Next i
' store the array for future use
m_array = vArray
End Sub
Public Function GetValue(rowKey, colKey) As Variant
If dictRows.Exists(rowKey) And dictColumns.Exists(colKey) Then
GetValue = m_array(dictRows(rowKey), dictColumns(colKey))
Else
Err.Raise 1000, "clsRangeToDictionary:GetValue", "The requested row key " & CStr(rowKey) & " or column Key " & CStr(colKey) & " does not exist"
End If
End Function
' return a zero-based array of RowKeys
Public Function RowKeys() As Variant
RowKeys = dictRows.Keys
End Function
' return a zero-based array of ColumnKeys
Public Function ColumnKeys() As Variant
ColumnKeys = dictColumns.Keys
End Function
I can now read the whole RequirementSet table into a dictionary and write a helper to obtain the particular requirement roughly so:
myDictionaryObject.GetValue(table1's RequirementSet, "MinHorsePower")
If someone could help me figure out how to put this into an answer giving the credit due to Tim Williams that'd be great.

SQLAlchemy getting label names out from columns

I want to use the same labels from a SQLAlchemy table, to re-aggregate some data (e.g. I want to iterate through mytable.c to get the column names exactly).
I have some spending data that looks like the following:
| name | region | date | spending |
| John | A | .... | 123 |
| Jack | A | .... | 20 |
| Jill | B | .... | 240 |
I'm then passing it to an existing function we have, that aggregates spending over 2 periods (using a case statement) and groups by region:
grouped table:
| Region | Total (this period) | Total (last period) |
| A | 3048 | 1034 |
| B | 2058 | 900 |
The function returns a SQLAlchemy query object that I can then use subquery() on to re-query e.g.:
subquery = get_aggregated_data(original_table)
region_A_results = session.query(subquery).filter(subquery.c.region = 'A')
I want to then re-aggregate this subquery (summing every column that can be summed, replacing the region column with a string 'other'.
The problem is, if I iterate through subquery.c, I get labels that look like:
anon_1.region
anon_1.sum_this_period
anon_1.sum_last_period
Is there a way to get the textual label from a set of column objects, without the anon_1. prefix? Especially since I feel that the prefix may change depending on how SQLAlchemy decides to generate the query.
Split the name string and take the second part, and if you want to prepare for the chance that the name is not prefixed by the table name, put the code in a try - except block:
for col in subquery.c:
try:
print(col.name.split('.')[1])
except IndexError:
print(col.name)
Also, the result proxy (region_A_results) has a method keys which returns an a list of column names. Again, if you don't need the table names, you can easily get rid of them.