Merge rows with connecting dates - matlab

I've got a large Excel sheet with customer and subscription data. From this table I would like to merge records/rows with connection stop_ and start_dates and show the result in a new worksheet. A simplified version of the data is shown below.
Customer_id subscription_id start_date stop_date
1034 RV4 30-4-2012 30-1-2015
1035 AB7 30-1-2014 30-3-2014
1035 AB6 30-1-2014 30-3-2014
1035 AB7 30-12-2013 30-1-2014
1035 AB7 12-12-2012 30-12-2013
1035 AB7 12-9-2010 14-1-2011
So, the formula has to check the customer_id and the subscription_id. When there is a match between two or more rows in the sheet and the stop_date of one of the rows overlaps with the start_date of the other row, then after the extraction and merging, one new row must be shown with the start_date of the first and the stop_date of the other row. This also has to work if there are multiple rows with connecting dates. All the rows that don't match these criteria stay the same after the extraction. So the result will be like this:
Customer_id subscription_id start_date stop_date
1034 RV4 30-4-2012 30-1-2015
1035 AB6 30-1-2014 30-3-2014
1035 AB7 12-12-2012 30-3-2014
1035 AB7 12-9-2010 14-1-2011
A dynamic solution would be ideal while new data will be added to the original sheet. While I know this is possible when you're certain that the rows you're looking for are always below each other, this is not the case here and it wouldn't give you a very dynamic solution.
So some kind of array function would be needed in Excel I guess but after searching a lot I couldn't find a suitable solution. I've also got MATLAB available but no clue where to start in that program with a problem like this.

A dynamic solution may be possible, but if the dataset it large it might bog things down quite a bit because you'd need it to run every time a cell was changed.
Basically the best way I can see to approach this is to create unique keys out your customer_id and subscription_id, then collect all of the date ranges under that key and merge them.
Something like this should get you started (requires a reference to Microsoft Scripting Runtime):
Public Sub LinkSubscriptionDates()
Dim data As Dictionary, source As Worksheet, target As Worksheet
Set source = ActiveSheet
Set data = GetSubscriptions(source)
Set target = source.Parent.Worksheets.Add
'Copy headers
target.Range(target.Cells(1, 1), target.Cells(1, 4)).Value = _
source.Range(source.Cells(1, 1), source.Cells(1, 4)).Value
Dim row As Long
row = 2
Dim key As Variant, item As Variant
For Each key In data.Keys
For Each item In data(key)
target.Cells(row, 1) = Split(key, "|")(0)
target.Cells(row, 2) = Split(key, "|")(1)
target.Cells(row, 3) = Split(item, "|")(0)
target.Cells(row, 4) = Split(item, "|")(1)
row = row + 1
Next item
Next key
End Sub
Private Function GetSubscriptions(source As Worksheet) As Dictionary
Dim subscrips As Dictionary
Set subscrips = New Dictionary
Dim row As Long
Dim cust As String, subs As String, starting As String, ending As String
'Gather all the data as pairs of customer|subscription, starting|ending
For row = 2 To source.UsedRange.Rows.Count
Dim dates() As String
cust = source.Cells(row, 1).Value
subs = source.Cells(row, 2).Value
'Valid customer/subscription?
If cust <> vbNullString And subs <> vbNullString Then
starting = source.Cells(row, 3).Value
ending = source.Cells(row, 4).Value
'Has an ending and starting date?
If starting <> vbNullString And ending <> vbNullString Then
Dim key As String
key = cust & "|" & subs
'New combo?
If Not subscrips.Exists(key) Then
subscrips.Add key, New Collection
subscrips(key).Add starting & "|" & ending
Else
subscrips(key).Add starting & "|" & ending
Set subscrips(key) = MergeDates(subscrips(key))
End If
End If
End If
Next row
Set GetSubscriptions = subscrips
End Function
Private Function MergeDates(dates As Collection) As Collection
Dim candidate As Long, index As Long
Dim values() As String, test() As String
Dim merge As Boolean
For index = 1 To dates.Count
values = Split(dates(index), "|")
'Check to see if it can be merged with any other row.
For candidate = index + 1 To dates.Count
test = Split(dates(candidate), "|")
If CDate(test(0)) >= CDate(values(0)) And _
CDate(test(0)) <= CDate(values(1)) Or _
CDate(test(1)) >= CDate(values(0)) And _
CDate(test(1)) <= CDate(values(1)) Then
dates.Remove candidate
merge = True
Exit For
End If
Next candidate
If merge Then Exit For
Next index
If merge Then
'Pull both rows out of the collection.
dates.Remove index
values(0) = IIf(CDate(test(0)) < CDate(values(0)), _
CDate(test(0)), CDate(values(0)))
values(1) = IIf(CDate(test(1)) > CDate(values(1)), _
CDate(test(1)), CDate(values(1)))
'Put the merged date range back in.
dates.Add values(0) & "|" & values(1)
'Recurse.
Set MergeDates = MergeDates(dates)
End If
Set MergeDates = dates
End Function
It really needs to be fleshed out with data validation, error trapping, etc., and it currently just puts the resulting data on a new worksheet. All the work gets done in the GetSubscriptions function, so you can just grab returned Dictionary from that and do whatever you need to do with that data in it.

Related

PowerPoint: Add Date of Yesterday and Tomorrow to a Slide

I want to have a table on my PowerPoint (2016) slide which should look like this:
sysdate - 1
sysdate
sysdate + 1
02.09.2021
03.09.2021
04.09.2021
To keep the slides intuitive, the dates should be updated automatically.
By using Insert -> Text -> Date & Time I can add a field containing the current date for the center column.
How do I add a dynamic field for yesterday and tomorrow?
First, follow the steps here to name your table. After that, insert a module (Alt+F11, Insert - Module) and add this piece of code:
Sub SetTableHeaders()
Const SlideNo = 1
Const TableName = "TableName Here"
Dim MyTable As Table
Set MyTable = ActivePresentation.Slides(SlideNo).Shapes(TableName).Table
MyTable.Rows(1).Cells(1).Shape.TextFrame.TextRange.Text = Format(Now - 1, "yyyy-mm-dd")
MyTable.Rows(1).Cells(2).Shape.TextFrame.TextRange.Text = Format(Now, "yyyy-mm-dd")
MyTable.Rows(1).Cells(3).Shape.TextFrame.TextRange.Text = Format(Now + 1, "yyyy-mm-dd")
End Sub
Replace the SlideNo and TableName values with the right ones. Run it (F5) to set the headers.

Need Concept to create a function using array or whatever you suggest- in sql server

Below is the example of Data.
ss-tt(1/21/2014 9:47:12 AM)->bb-tt-uu(02/07/14 11:09:59)
Above data is store in a column of a table. Now what I want to do ,to split "date" which is followed by "ss-tt" and paste it in another column but in same row.
For that i want to create a function in Sql server. It is quite easy in excel(VBA) to create a function using array but in Sql server i don't understand how to use the array concept.
Below is the function which i had created in excel(VBA) for the same calculation.
Sub readExcell1()
Dim arr() As Variant
Dim token As Variant
Dim innertoken As Variant
Dim first As String
Dim second As String
Dim ind As Integer
arr = Range("D2:D849")
Dim R As Long
Dim C As Long
rownum = 1
colnum = 1
For R = 1 To UBound(arr, 1) ' First array dimension is rows.
'MsgBox "processing row " & R
'MsgBox arr(R, 1)
token = Split(arr(R, 1), "->")
For i = LBound(token) To UBound(token)
'MsgBox token(i)
innertoken = Split(token(i), "(")
first = innertoken(0)
first = Trim(first)
second = innertoken(1)
If first = "payroll-apac" Then
ind = 1 + R
second = Replace(Trim(second), ")", "")
Application.Range("H" & ind).Value = second
GoTo Label1
End If
Next i
Label1:
Next R
End Sub
This should do what you want. Obviously you could handle the prefix and separator separately rather than use columns.
declare #table table (
[value] [nvarchar](max)
, [prefix] [sysname]
, [separator] [sysname]
, [calculated] as substring([value]
, len([prefix]) + 1
, charindex([separator]
, [value]) - len([prefix]) - 1));
--
insert into #table
([value]
, [prefix]
, [separator])
values (N'ss-tt(1/21/2014 9:47:12 AM)->bb-tt-uu(02/07/14 11:09:59)'
, N'ss-tt('
, N')');
--
select [value]
, [calculated]
from #table;

For each loop for a table in OpenEdge 10.2b takes more time

Below for each loop takes more time and i cant able to trace index usage using XREF as the table uses Oracle Schema.Please Help me.
Need to generate report for different Report Type ( Report type is the input parameter in my code ).Single report type may contain more than 50,000 records how to access all the record within minute.Index detail also mentioned below for each loop.
FOR EACH Report
FIELDS(EXTRACTDATE STATUS MailingType ReportType ReportNumber
RequestID CustID)
WHERE Report.EXTRACTDATE < Today
AND Report.ReportType = 'Customer Report'
AND Report.STATUS = 'Pending'
AND (Report.MailingType = "LETTER"
OR Report.MailingType = "Mail") NO-LOCK:
< Statements >
.
.
END.
**Index Detail**
CREATE INDEX "TYPE_IDX1" ON "Report" ("EXTRACTDATE" DESC, "ReportTYPE", "STATUS", "MailingTYPE", "PROGRESS_RECID")
CREATE INDEX "REQ_IDX1" ON "Report" ("REQUESTID", "PROGRESS_RECID")
CREATE INDEX "RTTYP_IDX1" ON "Report" ("ReportTYPE","PROGRESS_RECID")
The "OR" at the end will slow things down considerably - the AVM does better if you split it up into two sets of AND statements and OR the result, like so:
WHERE (Report.EXTRACTDATE < Today
AND Report.ReportType = 'Customer Report'
AND Report.STATUS = 'Pending'
AND Report.MailingType = "LETTER")
OR
(Report.EXTRACTDATE < Today
AND Report.ReportType = 'Customer Report'
AND Report.STATUS = 'Pending'
AND Report.MailingType = "Mail")

Add record to table, and edit records in 2 separate tables

Hi there I'm making an access database, and I can't figure out how to do one particular thing.
I've got a form with two text boxes: MovieID and CustomerID. I also have three separate tables: MovieList, CustomerInfo and HireHistory. What I need is so that when I enter a MovieID and CustomerID into the given boxes then press my button HireButton, it edits that specific MovieID's LastHireDate to Today(), edits that specific CustomerID's LastHireDate to Today(), and then in my HireForm (which has the CustomerID's in the first row) it adds a new record below the CustomerID in the form of: MovieID " on " Today()
Also, I need to make it so that it checks that MovieID's genre and if it's R16 or R18, then it checks whether the customer is older than 16 or 18 today, and if not then it comes up with an error box. I know how to do the checking whether they are older than 16 or 18, but not the error box.
I know that's a lot of text, so I'll just write what's in my brain (how I see the code should be) so it will be easier to see what I want to do.
IF MovieID.Rating = 'R16' OR 'R18'
THEN IF CustomerID.[Date(Year(DOB)+16,Month(DOB),(Day(DOB))] > Today()
THEN DISPLAY Msgbox = "Sorry, too young"
ELSE SET CustomerID.LastHireDate = Today()
SET MovieID.LastHireDate = Today()
ADDRECORD in HireHistory for that CustomerID to (MovieID & " on " & Today())
ELSE SET CustomerID.LastHireDate = Today()
SET MovieID.LastHireDate = Today()
ADDRECORD in HireHistory for that CustomerID to (MovieID & " on " & Today())
Does that explain it a bit better? Thanks in advance for your help! :)
so here How I would do this. You first have to create a recordset for each of those table.
For the age I would use this function. : http://www.fmsinc.com/MicrosoftAccess/modules/examples/AgeCalculation.asp
customerBirth = yourCode to get the date
If MovieID.Rating = 'R16' OR 'R18' then
If AgeYears(customerBirth) < 16 then
msgbox("Sorry, too young")
else
MyCustomerRecordSet("LastHireDate") = now
MyMovieRecordSet("LastHireDate") = now
MyHireRecorset.AddNew
MyHireRecorset("I don't know what your trying to do here")
MyHireRecorset.Update
end if
Else
MyCustomerRecordSet("LastHireDate") = now
MyMovieRecordSet("LastHireDate") = now
MyHireRecorset.AddNew
MyHireRecorset("I don't know what your trying to do here")
End if
If you have any question just ask.

Auto Populate fields in MS Access Form

Is there a way to automatically populate fields in an MS Access form? Lets say the user makes a selection from a specific combo box on the form, is there something that can be done to automatically select the other fields on the form based on the PK?
Id like to add that the fields to auto populate would come from various tables..
***ammendment
I need to return multiple values once i select a specific record in the combo box. Can someone help? The multiple values will come from a query that returns values like this:
ID Code Count
24 TST 4
24 BPB 7
24 SSS 10
In the form, the combo box would chose the ID number. Once I choose an ID number of 24, i want to return all 3 records above that come from a query called Project_Error_Final (in this example there are 3 values to return, but i want the query to return any records with ID = 24). The VBA code i have so far is:
Private Sub cboProjectID_Change()
Dim VarComboKey As Integer
Dim VarObjective As Variant
Dim VarStartDate As Variant
Dim VarEndDate As Variant
Dim VarRiskCategory As Variant
Dim VarTarDatSet As Variant
Dim VarErrorCount As Variant
Dim VarErrorCode As Variant
VarComboKey = Me.cboProjectID.Value
VarObjective = DLookup("[Objective]", "[Project_HDR_T]", "[Project_ID] = " & VarComboKey)
Me.txtObjective = VarObjective
VarStartDate = DLookup("[Start_Date]", "[Project_HDR_T]", "[Project_ID] = " & VarComboKey)
Me.txtStartDate = VarStartDate
VarEndDate = DLookup("[End_Date]", "[Project_HDR_T]", "[Project_ID] = " & VarComboKey)
Me.txtEndDate = VarEndDate
VarRiskCategory = DLookup("[Risk_Category]", "[Project_HDR_T]", "[Project_ID] = " & VarComboKey)
Me.txtRiskCategory = VarRiskCategory
VartxtTarDatSet = DLookup("[Targeted_Dataset]", "[Project_Targeted_Dataset]", "[Project_ID] = " & VarComboKey)
Me.txtTarDatSet = VartxtTarDatSet
VarErrorCount = DLookup("[Count_Error_Codes]", "[Project_Error_Final]", "[project_ID] = " & VarComboKey)
Me.txtErrorCount = VarErrorCount
VarErrorCode = DLookup("[ErrorCode]", "[Project_Error_Final]", "[project_ID] = " & VarComboKey)
Me.txtErrorCode = VarErrorCode
End Sub
The value in question is the VarErrorCount and VarErrorCode. In the VBA code above, only a single value is returned. But, I am looking for multiple VarErrorCount and VarErrorCode values to be returned in my form once the ID combo box field is selected. In this particular example VarErrorCode should return "TST", "BPB" and "SSS." The VarErrorCount should return the corresponding VarErrorCode values: "4","7","10"
With regards to your multiple returns, you can't use a DLookup, but I will show you how you can achieve the result you want, as per your description.
In this particular example VarErrorCode should return "TST", "BPB" and "SSS." The VarErrorCount should return the corresponding VarErrorCode values: "4","7","10"
Change your last 4 lines above the End Sub to the following:
Dim dbs as DAO.Database
Dim rst1 as DAO.Recordset
Dim rst2 as DAO.Recordset
Set dbs = CurrentDb
Set rst1 = dbs.OpenRecordset("SELECT [Count_Error_Codes] FROM [Project_Error_Final] WHERE [project_ID] = " & VarComboKey)
If rst1.RecordCount > 0 Then
rst1.MoveFirst
Do Until rst1.EOF
VarErrorCount = VarErrorCount & rst1!Count_Error_Codes & ","
rst1.MoveNext
Loop
' Remove the last comma
VarErrorCount = Mid(VarErrorCount, 1, Len(VarErrorCount) - 1)
End If
Set rst2 = dbs.OpenRecordset("SELECT [ErrorCode] FROM [Project_Error_Final] WHERE [project_ID] = " & VarComboKey)
If rst2.RecordCount > 0 Then
rst2.MoveFirst
Do Until rst2.EOF
VarErrorCode = VarErrorCode & rst2!ErrorCode & ","
rst2.MoveNext
Loop
' Remove the last comma
VarErrorCode = Mid(VarErrorCode, 1, Len(VarErrorCode) - 1)
End If
rst1.Close
Set rst1 = Nothing
rst2.Close
Set rst2 = Nothing
dbs.Close
Set dbs = Nothing
Me.txtErrorCount = VarErrorCount
Me.txtErrorCode = VarErrorCode
Yes there is!
Obviously, you need to be able to relate the combo box selection to the value you wish to be populated into the other field(s). Assuming that you have a 1:1 relationship with the PK (since you want to display only one value in your form), you can use the AfterUpdate event plus the DLookup() function to retrieve a related value using the PK.
As a simple example, I set up a table named Foods as follows:
FoodID, FoodName, FoodCategory
1, Orange, Fruits
2, Chicken, Poultry
3, Almond, Nuts
4, Lettuce, Vegetables
In the form, I have a control that selects the FoodID as the PK bound value named ComboFoods, and an unbound text box control named TextFoodCategory that we will populate with the FoodCategory from the Foods table.
I've assigned the following code to the AfterUpdate event of the Combo Box so that when the value of the combo box changes, the text box will be populated:
Private Sub ComboFoods_AfterUpdate()
'Create a variable to store the combo box primary key selection
Dim VarComboKey As Integer
'Create a variable to store the DLookup results
Dim VarFoodCat As Variant
'Capture the primary key of the combo box
VarComboKey = Me.ComboFoods.Value
'Retrieve the related field value
VarFoodCat = DLookup("[FoodCategory]", "[Foods]", "[FoodID] = " &
VarComboKey)
'Set the value of the text box to the variable
Me.TextFoodCategory.Value = VarFoodCat
This will return the FoodCategory that is related to PK. This is all using one table, but the DLookup statement can be modified to reference any query or table that contains the PK.
Please note that DLookup will only work properly when the PK is unique in the data you are referencing. It will not work in a one to many relationship unless you specify other criteria that restrict the results to one record. There are other ways to use SQL queries and recordsets within VBA if you need to return multiple records, but that this out of scope for this question.
This worked when tested - best of luck!