how to update an existing datatable in vb.net - datatable

hope you doing fine. I really need some help. actually I am developing a small application for creating invoices. one thing that I am finding really hard is when you have to edit an invoice. In my application, it generates an invoice number and you fill in the details such as description, qty, unit price and total amount. at first this is saved in the db, printed and shown to the head for approval. if there is any mistake, the user has to come back to the application and makes the changes for the invoice. this is where I am getting stuck. The application can recall the invoice. but once the changes made, I have to save it back to the db and this change can be for a specific record only. for instance,
invoice 001
serial descr qty unitprice total
1 paintx 2 2000 4000
2 painty 3 1000 3000
3 paintz 1 2000 2000
lets say there is a mistake and amendments to be done
serial descr qty unitprice total
1 paintx 2 2000 4000
2 painty 3 1000 3000
3 paintz 2 2000 4000
how am I supposed to make this change ?
any technique or logic I can use?
do I need to use datatable here?
please advise.

Well, you've given no clue as to the database technology/adapter you're using, but it should be something like...
con.Open()
cmd.Connection = con
cmd.CommandText = "UPDATE invoices SET serial = #serial, descr = #descr, qty = #qty ... etc... WHERE invoiceId = #invoiceId"
cmd.Parameters.AddWithValue("#serial", Form.txtSerial.Text)
cmd.Parameters.AddWithValue("#descr", Form.txtDescr.Text)
cmd.Parameters.AddWithValue("#qty", Form.txtQty.Text)
... etc...
cmd.ExecuteNonQuery()
Further reading: MSDN post on updating tables in VB.NET

Newfun()'Function for open the connection
Dim query As String = "update tBL_GageType set GageType = '" & name & "' where GID=" & id
Dim cmd As New OleDbCommand(query)
cmd.Connection = New OleDb.OleDbConnection(connectionString)
cmd.Connection.Open()
cmd.ExecuteNonQuery()

Related

Making DAX code more efficient - counting unique Start dates in overlapping date ranges

I have a table of every product purchased by every client over 25 years. The table contains client#, product, start date, and end date.
The products can be owned by the client for any amount of time (1 day to 100 years). While the client owns products with us, the client is active. If a client ends all products they cease to be a client. I want to count new client starts each year. The problem is, some clients end all products then start purchasing products again years later (but clients always retain the same client#) - If the client leaves then rejoins year's later I want to count the client as a new client.
I have created DAX code to do this which works perfectly on a small file, but the code uses up too many resources and so I cannot use it on my data (about 200,000 records). I know my code is HIGHLY INEFFICIENT and could probably be cleaned up...but I am not sure how. Alternately, if I could figure out how to make these columns in PowerQuery, perhaps that would work
Here is how I do it.
1) Add four calculated columns to my table:
VeryFirstStart = Calculate(
Min('Products'[StartDate]),
ALLEXCEPT(Products,Products[ClientNumber]))=Products[StartDate]
this flags records that contain the first ever start date of any client
MaxEndDateofEarlierDates = Calculate(
Max('Products'[EndDate]),
Filter(
Filter(ALLEXCEPT(Products, Products[ClientNumber]), Products[EndDate]),
Products[StartDate] < EARLIER(Products[StartDate])))
This step blows up my PowerBI - this shows the date of any NEW product purchases where the new start date occurs AFTER an ending date
Second+Start = And(
Products[MaxEndDateofEarlierDates]<>BLANK(),
Products[MaxEndDateofEarlierDates]<Products[StartDate])
this flags records where we want to count the new start date as a new client
NewStart = OR(Products[Second+Start],Products[VeryFirstStart])
**this flags ANY new client start date regardless of whether it was the first or a subsequent*
Finally I added this measure:
!MemberNewStarts = CALCULATE(
DISTINCTCOUNT(Products[ClientNumber]),
FILTER(
'Products',
('Products'[StartDate] <= LASTDATE('DIMDate'[Date]) &&
'Products'[StartDate]>= FIRSTDATE('DIMDate'[Date]) &&
Products[NewStart]=TRUE())))
Does anyone have any suggestions about how to achieve this with less resources?
Thanks
Here is some data to try
MemberNumber Product StartDate EndDate Note (not in real data)
1 A 02/02/2003 02/02/2004
1 C 02/02/2009 02/02/2010
2 A 02/02/2001 02/02/2002
2 C 02/02/2001 02/02/2002
2 B 02/02/2005 02/02/2010
3 C 02/02/2002 02/02/2005
3 B 02/02/2002 02/02/2005
3 A 02/02/2003 02/02/2008
4 B 02/02/2002 02/02/2003
4 C 02/02/2003 02/02/2006
5 B 02/02/2003 02/02/2007
5 C 02/02/2005 02/02/2010
5 A 02/02/2005 02/02/2007
6 A 02/02/2001 02/02/2006
6 C 02/02/2003 02/02/2007
7 B 02/02/2001 02/02/2004
7 A 02/02/2001 02/02/2005
7 C 02/02/2005 02/02/2006
8 B 02/02/2002 02/02/2006
8 A 02/02/2004 02/02/2009
note member 1 starts as a new client in 2009 since all previous products ended in 2004 and member 2 starts as a new client in 2005 since all previous products ended in 2002
The desired outcome is:
Start Year 2001 2002 2003 2004 2005 2006 2007 2008
New Clients 3 3 2 0 1 0 0 0
Here's one way of trying to solve it. Let me know if this is any more efficient than yours:
1st New Column:
PreviousHighestFinish:=
Calculate(
Max(Products[EndDate]),
ALLEXCEPT(Products,Products[ClientNumber]),
Products[StartDate] < Earlier(Products[StartDate]
)
This will give you the latest end date where the Client Number matches and the start date is before the current start date. If there is no earlier start date, it returns a blank.
2nd New Column:
NewClientProduct:=
if(Products[StartDate]>=Products[PreviousHighestFinish],1,0)
This will give you a 1 for every row where the client has either not been seen before (and the previous column showed blank) or the client has ben seen before, but has no current products.
The problem with this measure is that if you have a client starting more than one product on the same date, they will show as multiple new clients.
The fix for this is to count up the instances of each client-date combination
3rd New Column:
ClientDateCount:=
CALCULATE(
COUNTROWS(Products),
ALLEXCEPT(Products,Products[ClientNumber],Products[StartDate])
)
This essentially gives the number of times that the client on this row in the table has started a product on this date.
Now divide the 2nd new column by this one
4th New Column:
NewClients:=
DIVIDE(Products[NewClientProduct],Products[ClientDateCount])
And voila:

Anyway to iterate quickly over a collection of UDTs?

Let's say I have a collection of UDTs. I populate it as below:
public type udtEmp
Id as long
Name as string
end type
dim col as new Collection
dim empRec as udtEmp, empDummy as udtEmp
for n = 1 to 100000
empRec = empDummy ' reset record
emp.Id = n
emp.Name = "Name " & n
col.add emp, cstr(emp.Id)
next
Now I want to loop through it. I am using a Long data type as the index to .Item()
dim n as long
For n = 1 To 100000
emp = col.Item(n)
Next
The code above works, but it's really slow - takes 10,000 milliseconds to iterate. If I accessed the collection via a key, its much faster - 78 milliseconds.
For n = 1 To 100000
emp = col.Item(cstr(n))
Next
The problem is that when I iterate over collection, I don't have the keys. If I had a collection of objects instead of UDTs, I could do for each obj in col, but with UDTs, it won't let me iterate in that manner.
One of my thoughts was to have a secondary collection of indexes and keys to point to the main collection, but I am trying not to complicate the code unless I absolutely have to.
So what are my options?
the elegance of the code or the performance of it is a serious decision you have to make. the choice should be based on the impact of the results. for each is elegant but slow and goes with objects and classes. but if the speed is a mater then use UDT and arrays.
in your case, i think an array of UDT is best suited for your situation. and to gain more speed , try to access arrays using SAFE_ARRAY (that you can google for it), the result is much impressive.
You can use a user typed class collection. It'll provide the for-each iteration ability with great performance.
Easiest way to make that happen is through the Class Builder Utility (https://msdn.microsoft.com/en-us/library/aa442930(v=vs.60).aspx). You might need to first run the Add-in Manager and load the Class Builder Utility. (I think that there were install options regarding these features when you installed vb6/vs6? So if you don't see the Class Builder Utility in the Add-in manager it's could be due to that).
To match your udt sample, using the Class Builder Utility, first add a class (eg: Employee), with two properties (eg: EmpId and EmpName, long and string types respectively). Then add a collection (eg: Employees) based on the Employee class. Save it to the project (that will create two new class modules) and close the Utility.
Now you can create the new Employees collection, load it up, and iterate through it via index, key or for-each. (note: don't use a pure number for the key - requesting an item by a key that is a pure number, even as a string, will be interpreted as an index request, it'll be slow and you probably won't get the desired item)
Also - once the new classes have been created, you can add customized properties and methods to them to handle whatever kinds of fancy stuff you may have requirements for.
Dim i As Long
Dim Emp As Employee
Dim colEmp As New Employees
Dim name As String
' Loading
For i = 1 To 100000
colEmp.Add i, "name" & CStr(i), "key" & CStr(i)
Next i
' iterate with index
For i = 1 To 100000
Set Emp = colEmp(i)
name = Emp.EmpName
Next i
' iterate with key
For i = 1 To 100000
Set Emp = colEmp("key" & i)
name = Emp.EmpName
Next i
'iterate with for-each
For Each Emp In colEmp
name = Emp.EmpName
Next Emp
Timings
On my system for the above code:
Loading time: 1 second
Index time: 20 seconds
Key time: 0.29 seconds
For-each time: 0.031 seconds

VB6 Recordset "Open" taking more time to show result as compared to backend

I am using a query to find data.
Same query taking less time i.e 2 sec to execute from backend.
But in code same query taking more time i.e 30 sec in recordset.open.
Database : Sybase
Thanks
Code Sample :
Dim rsRoute As New ADODB.Recordset
---------------------------------------------
If rsRoute.State = 1 Then rsRoute.Close
Set rsRoute = New ADODB.Recordset
Set rsRoute.ActiveConnection = con
rsRoute.CursorLocation = adUseClient
rsRoute.CursorType = adOpenKeyset
rsRoute.LockType = adLockBatchOptimistic
strCmd = " select * from Table where CoumnVal =1 "
con.Errors.Clear
On Error Resume Next
rsRoute.Open strCmd
There are several types of CursorsType and two different CursorLocation varieties. On the Sybase database (ASE back in the day) the performance differs wildly depending on what you choose. Try both client-side and server-side cursors and see what happens.
If you just need to loop through the result once, select the adOpenForwardOnly cursor type. It usually results in the best performance.
EDIT: Based on the code you posted, try a) not locking anything (e.g LockType), b) using a adOpenForwardOnly cursor, a) the keep the cursor on the server (adUseServer)

ASP.NET GridView fail to sort a Date passed as string

Hi I am building a site which has a gridview with AutoGenerateColumns = True, the issue that I am having is the Sort condition using a dataview does not work correctly for example. If I have the following records already displayed on the gridview:
Name Address Date (MM/DD/YYYY)
Julio XYZ Australia 12/25/2010
David 1234 New Zealand 12/26/2010
Erika 5555 Singapore 12/14/2011
If I do the sorting this way:
Dim dt As DataTable = Me.GetDataTable(Me.GetQuery(Sentence, params))
Dim dv As DataView = dt.DefaultView
dv.Sort = SortExpression & " " & SortDirection
gv.DataSource = dv
gv.DataBind()
The result in the grid is :
Name Address Date (MM/DD/YYYY)
Erika 5555 Singapore 12/14/2011
Julio XYZ Australia 12/25/2010
David 1234 New Zealand 12/26/2010
So the problem it seems to be the sort is only taking in consideration part of the date only the first five characters instead of the whole string.
The values for SortExpression is the ColumnName for Date which in the datasource is CallDate and the SorDirection Value is ASC
The Me.GetDataTable(Me.GetQuery(Sentence,paramas)) is just a way to populate the datatable with the records from the Database.
Another thing, sadly I cannot change the format of the Date because is a business requirement to be presented that way, also I am not allow to use third party controls because the budget of the project. :-(
Thanks for the any idea in advance.
First I want to confirm that whether your Date is DateTime type, if yes,
please try to sample as below, hope these will give you a hand.
Dim dt As DataTable = Me.GetDataTable(Me.GetQuery(Sentence, params))
dt.DefaultView.Sort = "Date ASC" ''Sort with Asc.
gv.DataSource = dt
gv.DataBind()

How to get sets of Records in VB6?

Hey guys, just want to ask you a simple question that I know you're familiar with... I am using VB6, I just want to get sets of records from my database. What I mean is that I have UserID and with a part of code provided below, it only gets a single set of record. Like for instance, the value of UserID is A12, and so, all sets of records with the UserID of A12 must display in Textboxes respectively with the aid of datPayroll.Recordset.MoveNext.
With datPayroll
.RecordSource = "select * from tblpayroll where empid like '" & UserID & "'"
.Refresh
Me.txtRegularHours.Text = .Recordset.Fields!reghours
End With
-datPayroll : DataControl
-txtRegularHours : Textbox
-UserID : Variable
You probably want to look at MoveFirst, MoveNext, etc. and also EOF
Here is a link or two to get you started:
EOF, BOF
MoveFirst, MoveNext
You need to check that you have some data in your Recordset using EOF, then MoveFirst to move to the first record, and loop through using MoveNext.

Resources