VB statement fails to update field in Access 2016 - database

The problem is with data fields need to be checked to determine if the "Transaction_Amount" is an expense or Income. This information is stored in the "categories" and the table associates a budget category as an "expense/Income".
Based on the "Income/expense" notation the actual transaction amount is populated as an expense (-) or Income (+) and updated in the "Account_Trasactions" table as either an expense or Income Item. In each case, the value is added to the existing value in the Account_Transactions" Table in the record associated with that budget.
So the goal is to track all budget categories as "budgeted" - "actual" = "Balance".
Here is my code and it fails to update the field Actual_amount on the form!
Private Sub Actual_amount_GotFocus()
'check for expense or income and adjust actual ammount of transaction'
[iif [category].[income/expense]="expense", (actual_Amount)=((Transaction_amount)*-1),actual_amount = Transaction_amount)]
'Update category table'
[Category].[Actual_Amount] [Actual_Amount]
End Sub
What am I doing wrong??

Related

How to determine id date falls under one of the ranges (ranges are stored in separate rows of another table)

I have SalesFacts Table, which contains Sales_Amount, Customer_ID and Invoice_Date.
In another table I have Information's about special agreements for some of the customers (columns are: Customer_ID, Agreement_Start_Date, Agreement_End_Date).
Now - i would like to check, if the sales from SalesFact table occurred when special agreement was active for the Customer. This would be pretty easy, if there was only one date range when special agreement was active. However, in my case, Table with Special Agreements date ranges contains duplicated Customer ID, because for one Customer there might be several time ranges, where special agreement was active.
E.G. In SalesFact Table I have 3 transactions for one customer:
In SpacialAgreements Table I can see, that there are 2 data ranges when this customer had a right to special agreements.
I would like to create a query, that adds additional column to my SalesFacts table, that would determine, if the transaction happened when there was a Special Agreement Active. So in case shown above, it would be:
If there was Only one date range with special agreement it would be pretty easy:
Select
S.[Sales_Amount], S.[Customer_ID], S.[Invoice_Date],
IIF(S.[Invoice_Date] >= A.[Agreement_Start_Date] and S.[Invoice_Date]<=A.[Agreement_End_Date],'YES','NO') as AGREEMENT
From SalesFacts S left join SpacialAgreements A on S.[Customer_ID] = A.[Customer_ID]
But since there are several date ranges in SpacialAgreement table, i don't know how to achieve that properly, without risking any duplicates in Sales_Amount and without loosing any data.
Any ideas?
If you want to get data exactly as you shown in question then for the SELECT statement you can use something like this:
SELECT
S.[Sales_Amount],
S.[Customer_ID],
S.[Invoice_Date],
CASE WHEN EXISTS (SELECT 1
FROM SpacialAgreements A
WHERE A.Customer_ID = S.Customer_ID
AND S.[Invoice_Date] >= A.[Agreement_Start_Date]
AND S.[Invoice_Date] <= A.[Agreement_End_Date])
THEN 'YES'
ELSE 'NO'
END as Agreement
FROM SalesFacts S
So, this solution can be used if you are selecting data or creating view from this query.
If you want to have persisted value as one physical column in your SalesFacts table then you can try to solve your problem with triggers.

Update changes to related tables in VB.Net

I have two related SQL tables, both of which I open with a dataadapter and fill into a dataset. I set the relationship as follows:
DS.Relations.Add("RBT", DS.Tables("Jobs").Columns("ID"), DS.Tables("BillTech").Columns("JobID"), False)
Dim BSBT As New BindingSource
BSBT.DataSource = BS
BSBT.DataMember = "RBT"
The ID column in the Jobs SQL table is an identity seed incremented by 1.
The columns from the Jobs table are displayed on a form with a binding navigator to move from job to job. The related columns from the BillTech table are displayed in a datagridview on the Jobs form.
If the user adds a row to the datagridview (i.e. a new row to the BillTech table) for an existing job, I put the ID from the selected job into the JobID column of the datagridview in the DefaultValuesNeeded event of the datagridview. That all works great.
The problem is when the user adds a new job to the Jobs table and then tries to add a new row in the datagridview for that new job. Since the ID of that new job is unknown (since it hasn't been updated back to the SQL table), I use the dataadapter to update the Jobs table and then retrieve the assigned ID from the updated SQL table using the "GetNewJobID" function. I then try to insert that value in the new row of the datagridview. See the code below:
Private Sub DataGridView2_DefaultValuesNeeded(sender As Object, e As DataGridViewRowEventArgs) Handles DataGridView2.DefaultValuesNeeded
Dim JobID As Integer = 0
With e.Row
Dim DR() As DataRow = DS.Tables("Jobs").Select("Name = '" & Replace(Me.JobName.Text, "'", "''") & "'")
If DR.Length = 1 Then
JobID = DR(0).Item("ID")
Else
Dim Name As String = Me.JobName.Text
BS.EndEdit()
DA.InsertCommand = CB.GetInsertCommand
DA.Update(DS.Tables("Jobs"))
'Because we have already added this job to the database, we keep a list so we can see if the user wants this job added to QB.
If NewJobs.Contains(Name) = False Then
NewJobs.Add(Name)
End If
JobID = GetNewJobID(Name)
End If
.Cells("JobID").Value = JobID
End With
End Sub
I get an error on the next to last line of the above sub ".Cells("JobID").Value = JobID saying that the column "JobID" does not exist. Since this only occurs when adding a BillTech row to a new Job Row, I'm guessing that by updating the Jobs SQL table, this somehow breaks the connection to the datagridview?
How can I update this properly? I've looked at TableAdapterManager, but this seems to only work with typed datasets. Because these SQL tables are on a Windows Server 2003 server, I cannot bring them in with an "Add New Datasource" wizard.
I'll pick on the typical parent/child or master/detail of Customers:Orders. If you were using an access or sql server db with a relationship defined in the db and you made a new dataset, opened it in the designer, right clicked the surface and chose Add TableAdapter, put SELECT * FROM customers and repeated the process (from right click..) for Orders you would end up with a Customers DataTable and TableAdapter, an Orders DataTable and TableAdapter and a DataRelation between the two linking (say) orders.customerid to customers.id
Save the set, then take a look in the data sources window and expand every node.
There is a top level node of Customers and a top level node of Orders, and you'll also notice an Orders node that is a child of Customer
Drag the Customers node out of datasources, onto a new form. A customersdatagridview, dataset, customerstableadapter, customersbindingsource and customersbindingnavigator appear. Delete the navigator (for clarity right now). You will note that the customersdatagridview is bound to the customersbindingsource and the customersbindingsource is bound to the Customers table of the dataset
Drag the top level Orders out of the datasources window onto the form. You'll notice that an ordersdatagridview, ordersbindingsource, orderstableadapter and ordersnavigator appear. Delete the navigator. Note that, like before, the ordersdatagridvew binds to the ordersbindingsource and the ordersbindigsource binds to Orders in the dataset. This is what I think you've done
Delete everything that appeared when you dragged Orders out (dgv/bs/ta for orders). Don't delete the dataset - it's still in use by hings named customers*
Now go back to the datasources window and this time drag the child Orders out that is below the Customers node. The same components appear (ordersdgv/bs/ta/nav). Delete the nav. Look at the ordersbindingsource datasource and datamember properties this time. You'll notice that unlike last time, this ordersbindingsource is not bound to the dataset directly but to the customersbindingsource, specifically to a datamember named after the same name as the datarelation in the set
In this setup, when the parent current row changes in the customersbindingsource, the ordersbindingsource will only see a filtered set of orders rows - the filter passes only rows whose orders.customerid is equal to the current id in th customersbindingsource
Note; it's important that the Orders data has to be in the dataset. Nothing here automagivally downloads database data. If you fill customers but don't fill the orders data then no data will show in the orders, no matter how it is bound.
The simplistic approach takes the default queries in the tableadapters (select * from customers, select * from orders) and dwnloads the ENTIRE db into the dataset. It'll work for demonstration purposes but you really don't want to do that in a production program.
Go back to the dataset and alter the default queries in the table adapters to be SELECT * FROM customers WHERE id = #id and the corollorary for orders. Then add ANOTHER query to the customers TA (right click it and choose add query):
SELECT * FROM customers WHERE lastname = #lastname
Call this query FillByLastName (the wizard will ask you to name it and suggest FillBy. Don't accept the default; give it a sensible name)). This might load 10 customers.
Now go to the ORDERS tableadapter and add another query to that too:
SELECT * FROM orders WHERE customerid = #customerid
Call it FillByCustomerId. This can be used, once we have loaded 10 customers, to retrieve the orders for those 10 customers:
'fill the form dataset with customers named smith:
Me.someDataSet.Clear()
customersTableAdapter.FillByLastName(someDataSet, "Smith") 'it will fill the Customers table with Smiths
ordersTableAdapter.ClearBeforeFill = false 'turn this off or every call to fill will remove existing order from the datatable
For Each cro as CustomersRow in someDataSet.Customers 'for all our smiths
ordersTableAdapter.FillByCUstomerId(someDataSet, cro.Id) 'fill orders for customer with that id
Next cro
So now you have 10 customers, and maybe 50+ orders - you don't have the whole DB in your dataset, just the interesting data. Databinding via the datarelation exposed on the customers bindingsource will take care of showing only the related rows. Click on various rows in the customers datagridview and note that the orders shown in the ordersdatagridview changes to show only the relevant rows
It is intended that you add as many queries to a tableadapter as suits your needs. You could, rather than looping the customers and filling their orders by each customer ID, write a query that returns them all in one hit, on the ORDERS tableadapter:
SELECT orders.*
FROM
orders INNER JOIN customers on orders.customerid = customers.id
WHERE
customers.lastname = #lastName
The query selects only data from orders, but joins through to customers and searches on customer last name, so we should call this FillByCustomerLastName
Our code could then look like:
'fill the form dataset with customers named smith:
Me.someDataSet.Clear()
customersTableAdapter.FillByLastName(someDataSet, "Smith") 'it will fill the Customers table with Smiths
ordersTableAdapter.FillByCustomerLastName(someDataSet, "Smith") 'fill orders for all customers with a last name of smith
Horses for courses which you choose. I tend to pick the first approach and loop because it's more flexible, but where outright performance matters it can be faster to use a pattern like the second

SSIS SCD Transform Start Date and End date are the same - how can this be?

I have an issue with my ETL.
I have a dimension table that has some SCD 1 and SCD 2 columns - I have mapped these correctly in the SCD Transformation as Changing Attribute and Historical Attribute respectively.
Then on the Historical Attribute Options page I have checked the Use start and end dates to identify current and expired records, inputting my ValidFrom column as the Start date column and my ValidTo column as the End date column.
As I understand it, this should mean that any inserted records are given a ValidFrom of the current datetime value and their ValidTo column remains NULL. And for those who already exist but are the outdated record, their ValidTo becomes the current datetime value.
However, on some but not all records that get imported - the latest record inserted is inserted with the exact same datetime in the ValidFrom and ValidTo record.
Which becomes an enormous pain as I am left to view that record as invalid in my queries, and the knockon effect on fact table loading.
Can anyone help as to why this is happening?

SQL Server indexed calculated column that sums another table

I'd like to effectively add a calculated column, which sums a column from selected rows in another table. I need to to quickly retrieve and search for values in the calculated column without re-computing the sum.
The calculated column I'd like to add would look like this in Dream-SQL:
ALTER TABLE Invoices ADD Balance
AS SUM(Transactions.Amount) WHERE Transactions.InvoiceId = Invoices.Id
Of course, this doesn't work. My understanding is that you can't add a calculated column that references another table. However, it appears that an indexed view can contain such a column.
The project is based on Entity Framework Code First. The application needs to quickly find non-zero balances.
Assuming an indexed view is the way to go, what is the best approach to integrating it with the Invoices and Transactions tables to make it easy use with LINQ to Entities? Should the indexed view contain all the columns in the Invoices table or just the Balance (what gets persisted)? A code snippet of the SQL to create the recommended view and index would be helpful.
An indexed view won't work because it would only index expressions in the GROUP BY clause, which means it can't index the sum. A computed column won't work because the sum can't be persisted or indexed.
A trigger works, however:
CREATE TRIGGER UpdateInvoiceBalance ON Transactions AFTER INSERT, UPDATE AS
IF UPDATE(Amount) BEGIN
SET NOCOUNT ON;
WITH InvoiceBalances AS (
SELECT Transactions.InvoiceId, SUM(Transactions.Amount) AS Balance
FROM Transactions
JOIN inserted ON Transactions.InvoiceId = inserted.InvoiceId
GROUP BY Transactions.InvoiceId)
UPDATE Invoices
SET Balance = InvoiceBalances.Balance
FROM InvoiceBalances
WHERE Invoices.Id = InvoiceBalances.InvoiceId
END
It also helps to provide a default value of 0 for the Balance column since when you mark it as DatabaseGeneratedOption.Computed, EF won't provide any value for it when adding an Invoice row.

One more question regarding triggers PL/SQL

I have run into a problem with a second trigger we are to write regarding the following:
I have just written a stored procedure and stored function that serve to insert a new row into my Orders table. The row update inserts: Ordernum, OrderDate, Customer, Rep, Manufacturer, Product, Qty, and SaleAmount.
I now have to write a trigger that updates my Offices table by adding the amount of the newly added sale. Problem is, not every salesrep has an office assigned to them. I don't understand if I need to have a when clause under 'FOR EACH ROW' which somehow stipulates this, or if I need to stipulate after my SET Sales line. This is my code so far, but unfortunately, it updates all of the offices sales, not just the one that the salesrep belongs to:
CREATE OR REPLACE TRIGGER UpdateOffices
AFTER INSERT ON Orders
FOR EACH ROW
BEGIN
UPDATE Offices
SET Sales = Sales + :NEW.Amount
WHERE Office IN (SELECT RepOffice
FROM Salesreps
WHERE RepOffice IS NOT NULL);
End;
/
SHOW ERRORS
Sales is the name of the column on the Offices table. Amount if the name used in the stored proc.
You've already been advised to add a predicate on Salesreps, e.g. WHERE Salesrep = :NEW.Rep. Why don't you add it to the subquery?
You are going to run into all sorts of problems implementing your solution using this trigger method.
The Office.Sales column value will become stale as soon as amendments to orders are committed to the database. For example, when the price or quantity on an order is changed or deleted.
I would recommend you implement this requirement as a 'Refresh on Commit' Materialized View.

Resources