SSRS Median and drill down reports - sql-server

I have a SQL Server Reporting Services report in which I calculate the median using an ArrayList in a custom code block as median is not a built in function in SSRS. The median and average are displayed in a column chart. The report includes a drilldown to a detail report. If I drill down to the detail report and then hit the back arrow in the browser to navigate back to the master report, the median on the master report is not being calculated. That column of the column chart is empty while the average is displayed as it should.
Does anyone have any thoughts on why this is happening or how I can fix it?
The code is below. AddValue() first creates a new SortedList of it doesn't already exist. It then adds the newValue to an ArrayList keyed by the string passed to the function, creating one if it didn't previously exist. Each ArrayList represents a different set of values for which we would want to calculate the median.
GetMedian() calculates the median for the ArrayList identified by the passed string. GetMedian() is used in the value for the column in the chart.
Public Dim ClearanceList As System.Collections.SortedList
Function AddValue(ByVal whichList As String, ByVal newValue As Integer) As Decimal
Dim thisList As System.Collections.ArrayList
If (ClearanceList is Nothing) Then
ClearanceList = New System.Collections.SortedList
End If
If (ClearanceList.ContainsKey(whichList)) Then
'Get a reference to the desired ArrayList and add the new value to it.
thisList = ClearanceList.GetByIndex(ClearanceList.IndexOfKey(whichList))
Else
thisList = New System.Collections.ArrayList()
' Create a new element in the SortedList
ClearanceList.Add(whichList, thisList)
End If
thisList.Add(newValue)
AddValue = thisList.Count
End Function
Function GetMedian(ByVal whichList As String) As Decimal
Dim thisList As System.Collections.ArrayList
Dim count As Integer
thisList = ClearanceList.GetByIndex(ClearanceList.IndexOfKey(whichList))
count = thisList.count
If (count > 0) Then
thisList.Sort()
If count Mod 2 = 1 Then
GetMedian = thisList((count - 1) / 2)
Else
GetMedian = (thisList((count / 2) - 1) + thisList((count / 2))) / 2
End If
Else
GetMedian = -1
End If
End Function

Related

How to retrieve a VB Control instance, given its Name and Index?

If I have a string "cboEnoughMoney(0)", is it possible to retrieve the control from a control array that I have in my form, cboEnoughMoney?
In my code, I try to refer to the control in this way:
frm.Controls(sControlName).ListIndex = -1
sControlName in this case is "cboEnoughMoney(0)" and I get an error that the control was not found.
EDIT: One of the issue's i'm having is trying to as above set the .listindex to -1, another one is where I actually try to get and set value to the combobox. In a function - i pass form name as parameter called frm.
In the code what has been done is this....
dim ctlData as string
If Frm.Controls(RS!CTRLname).ListIndex > 0 Then
CtlData = Frm.Controls(RS!CTRLname).Value
Else
CtlData = ""
End If
Any idea how I'd be able to do that with cboEnoughMoney(0)....
I assume I could follow your example and check
if instr(1,RS!CTRLname, "(")
but if there is, how would I refer to that particular control in frm
It is just enough to look in the VB Properties Window: if you search "cboEnoughMoney(0)" you will find "cboEnoughMoney"(0) (without double quotes). Still the name is the same as a non-array control.
So, it is perfectly legal to refer to a VB Control with Name and Index, no need for a controls loop here:
If isControlsArray Then
Set ctrl = Me.Controls(Name)(Index) '// array
Else
Set ctrl = Me.Controls(Name) '// non array
End If
You cannot use the (index) part in a lookup via .Controls.
You can loop them manually & given that you can safely assume any control name with a ( is an array member and thus will have an Index property match on that:
Private Function GetControl(ByVal name As String) As VB.Control
Dim pos As Long: pos = InStr(name, "(")
If pos = 0 Then
Set GetControl = Me.Controls(name) '// non array
Else
Dim index As Long
index = Val(Mid$(name, pos + 1)) '// get index #
name = Left$(name, pos - 1) '// get base name
For Each GetControl In Me.Controls
If (GetControl.name = name) Then
If (GetControl.index = index) Then Exit Function
End If
Next
Set GetControl = Nothing
End If
End Function
And then:
GetControl("cboEnoughMoney(1)").ListIndex = -1

How do I sort an array of different times?

So I have an array of various timeslots, but I want to sort out the times from the earliest ones to the latest ones, however, I also want to delete any elements within the array that has the time value of 12:00am.
Appointment(0) = #10:45:00 AM#
Appointment(1) = #12:00:00 AM# 'My actual has up 80 elements of different timeslots but I'm using 3 elements as an example
Appointment(2) = #12:00:00 AM#
Is there anyone who can help me with this problem?
Using a string array is not a good idea if that's what you used just use a list of DateTime and the Sort method.
Dim list As List(of DateTime) = new List(of DateTime)
For Each val As String In Appointment
list.Add(val.replace(" ",""))
Next
list.Sort(New Comparison(Of Date)(Function(x As Date, y As Date) y.CompareTo(x)))
Nothing in .Net for removing specific items from array, but it can be "simplified" a bit with LINQ:
Dim Appointment = {#10:45#, #12AM#, #12AM#}
Appointment = (From a In Appointment Where a <> #12AM# Order By a).ToArray
or
Appointment = Appointment.Except({#12AM#}).ToArray
Array.Sort(Appointment)
A bit more efficient alternative can be to use generic collection like List or SortedSet instead:
Dim list = New List(Of Date) From {#10:45#, #12AM#} ' or Dim list = Appointment.ToList
list.Add(#12AM#)
list.RemoveAll(Function(a) a = #12AM#)
list.Sort()

How do i pass values from view model to controller without use of list?

Continuing from my previous question, i pass the id value from 'Lookup' controller to another controller method 'Charges'.
Function Charges(id As String) As ActionResult
Dim Patient As New LookupVM()
Patient.GetHistory(paid)
Return View(Patient)
End Function
In the view model, i have the GetHistory(id) list method, and listProcedure is the list holding the values that i want to pass back to the controller to be displayed in the view.
Public Property listProcedure As List(Of LookupVM)
Public Function GetHistory(id As String) As List(Of LookupVM)
Using db As New DbContext()
' SQL query
'====================
Dim idd = New SqlParameter("#id", "%" & id & "%")
Dim query As String = "select p.id id, pv.pvid pvid
from patient p
join patient_visit pv on p.id = pv.id
where p.paid like #id"
Dim Results = db.Database.SqlQuery(Of LookupVM)(query, idd).ToList()
For Each item In Results
Dim pvid = New SqlParameter("#pvid", "%" & item.pvid & "%")
Dim query2 As String = "select po.remarks remarks, po.entereddt entereddt, po.Consultant Consultant
from procedure_order po
join procedures p on po.pdid = p.pdid
where po.pvid like #pvid
order by po.entereddt desc"
Dim Results2 = db.Database.SqlQuery(Of LookupVM)(query2, pvid).ToList()
For Each item2 In Results2
Dim ProcedureList2 As New LookupVM()
ProcedureList2.remarks = item2.remarks
ProcedureList2.entereddt = item2.entereddt
ProcedureList2.ForConsultant = item2.ForConsultant
listProcedure.Add(ProcedureList2)
Next
Next
Return listProcedure
End Using
End Function
I'm wondering if i'm able to pass those values to the controller through something else other than a list. if possible, what could it be? Because if its a list, i can't display them on the page without the use of foreach loop.
Another question is, is my code conceptually correct or wrong? Because when i run, it took me 5 minutes to display a list of 72 values which involves the code above. I think it took way too long. Is there any way to make it load faster?
About the List, there is nothing wrong with doing For Each in a View. If it is needed then it is needed, and no reason to avoid it.
Some query tips (it is hard to do better for lack of details):
If your paid and pvid columns are INT, then do not query them using LIKE #id but using = #id (without % in it). Even if they are (N)VARCHAR then using LIKE would need to be justified and explicit. If done by accident then output will often be wrong.
LIKE '%value%' causes indexes to be ignored, possibly leading to bad performance.
Make sure that you have indexes on the columns that you use to JOIN on.
Try combining the two queries into one, to limit the number of .NET/DB roundtrips.

reference dictionary within array output to listbox

Title kind of states my problem.
I'm using an Api (For Vertical Response, an email list manager) which works fine. But for a particular method returns an Array where the information I need to reference is within a Dictionary inside that Array.
Array[list_id, list_name, list_type, member_data] <- member_data being the dictionary housing all my goodies.
Best I've managed to get is the listbox outputting "com.verticalresponse.api.NVPair[]" for each member.
Code
Protected Sub GetBounces()
Dim listID As Integer = 284662333
Dim isMember As Boolean = False
Dim newSession As New loginArgs()
newSession.username = username
' Your VerticalResponse username
newSession.password = password
newSession.session_duration_minutes = "120"
Dim VRUser As New VRAPI()
Try
sessionID = VRUser.login(newSession)
Dim GetMembers As New getListMembersArgs()
Try
GetMembers.session_id = sessionID
GetMembers.list_id = listID
GetMembers.max_records = 8
Try
Dim listmembers As Array = VRUser.getListMembers(GetMembers)
lstBounces.DataSource = listmembers
lstBounces.DataValueField = ("member_data").ToString()
lstBounces.DataBind()
Catch ex As Exception
lstBounces.Text = "One: " + ex.ToString()
End Try
Catch listex As Exception
lstBounces.Text = "Two: " + listex.ToString()
End Try
Catch ex As System.Exception
lstBounces.Text = "Three: " + ex.ToString()
End Try
End Sub
Edit
I have taken the suggestion of Keith Mifsud and added a breakpoint just before the Databind. It shows me that "listmembers" has eight indices (currently only testing by searching for 8 (total list will be close to 8000, of which about 1900 are needed.))
Each of those 8 indices contains the 4 columns I am looking at, so when I use listmembers(3) as the datasource I'm really only searching the fourth result, not the member_data column...
Is there a correct way to reference the column of results?
Something like:
lstbounces.DataSource = listmembers( ,3)
But instead of that, a correct one?
I think you should set the datasource as the dictionary not the array holding it
Try
Dim listmembers As Array = VRUser.getListMembers(GetMembers)
lstBounces.DataSource = listmembers(3)
'As the datasource is a dictionary, I don't think you have to set up the display and value fields
'lstBounces.DataValueField = ("member_data").ToString()
lstBounces.DataBind()
Catch ex As Exception
lstBounces.Text = "One: " + ex.ToString()
End Try
UPDATE
Based on what the collection type (dictionary within every element of an array) I would recommend you use the .net DataView with allows for expandable rows. There are some very good tutorials which can guide you to create your view

Searching an Array in Word (Visual Basic for Applications)

I have set up three arrays in Word. The arrays are as follows:
tacData = Array("32064600", "33001000", "33001100", "33002400", "33003000", "33002400", "35011001", "35013200", "35124100", "35124100")
makeData = Array("Alcatel", "Alcatel", "Sagem", "Samsung", "AEG Mobile", "Samsung", "Nokia", "Maxon", "Siemes", "Nokia")
modelData = Array("One Touch EasyHD", "91009109MB2", "RC410G14", "SGH-200", "Sharp TQ6", "SGH-5300", "DCT-3", "MX6832", "MC399 Cellular Termnial", "DCT-4")
I have made a user form which get a TAC (Value) from the User. Can I get this value and search for it in the first array and get its ID so that I can get the make and model from the other two arrays? I have tried using some code samples that I found but they do not seem to work with Word throwing errors. They were things like Application.Match.
On a side note, would there be a better way to store this information rather than three arrays?
I think you need a collection object. Look at the code below
Dim tacData() As Variant, makeData() As Variant, modelData() As Variant
tacData = Array("32064600", "33001000", "33001100", "33002400", "33003000", "33002401", "35011001", "35013200", "35124100", "35124101")
makeData = Array("Alcatel", "Alcatel", "Sagem", "Samsung", "AEG Mobile", "Samsung", "Nokia", "Maxon", "Siemes", "Nokia")
modelData = Array("One Touch EasyHD", "91009109MB2", "RC410G14", "SGH-200", "Sharp TQ6", "SGH-5300", "DCT-3", "MX6832", "MC399 Cellular Termnial", "DCT-4")
Dim i As Integer, N As Integer
N = UBound(tacData, 1) 'Get the data size
Dim item As Phone 'Temp variable for creating elements into a collection
Dim list As New VBA.Collection 'Define a new collection
For i = 1 To N
Set item = New Phone 'Assign a new Phone object
With item
.TAC = tacData(i) 'Assign values to the phone
.Make = makeData(i)
.Model = modelData(i)
End With
list.Add item, item.TAC 'Add the phone to the list with a KEY
Set item = Nothing
Next i
Dim TAC As String
TAC = "33002400" 'get user input
Set item = list(TAC) '** lookup Phone using Key **
If Not item Is Nothing Then ' Show results
Debug.Print item.TAC, item.Make, item.Model
Else
Debug.Print "Not Found"
End If
It works with a new class called 'Phone' containing
Option Explicit
Public TAC As String
Public Make As String
Public Model As String
and inserted into VBA via this menu item, and renaming in the project tree as "Phone"
The requirement is that the 'TAC' code is unique. In your case it wasn't and I had to change some numbers to make them unique. How have to consider what to do if in real life there are multiple phones with the same TAC code.
PS. Welcome to the world of object oriented programming. This was your first step.

Resources