SSRS update a record - reporting-services

So we have a SSRS report that displays some information about a product but we will like to update said product. The example I was given goes as follows
Name
Location
Price
Action
Orange
Earth
$100
Update
After clicking the Update word ... the price value changes.
Name
Location
Price
Action
Orange
Earth
$150
Update
Im hoping I can link the word "Update" to a stored proc that we have that will do all the magic.
Thanks

You can do this but it is not elegant.
I'm assuming you need some way of providing the new price, so that could be a parameter.
Let's take an example where you provide a price increase or decrease as a simple parameter in your report which is going to be passed to a stored proc along with the item selected in order to do the update.
First step is to create a report which looks like the example you provided. Add a parameter to this called say, pPriceAdjust. Allow blank values and set blank by default. We need to do this so the report runs initially without a parameter value being set.
Once that report looks OK, leave it to one side for now, we'll come back to that later.
Now create a new report, let's call it _sub_PriceAdjust. Add 4 parameters called pName, pLocation, pPrice, pAdjustment .
Next add a dataset query that look something like this..
UPDATE myTable SET Price = #pPrice + #pAdjustment
WHERE [Name] = #pName and [Location] = #pLocation
SELECT CONCAT(#pName, ' in location ', #pLocation, ' was updated from ', FORMAT(#pPrice, 'c2'), ' to ', FORMAT(#pPrice + #pAdjustment, 'c2')) as ReturnText
You could (and probably should) create a stored proc to do this but for the sake of simplicity it can just go directly in the dataset query.
All we have done is updated the record and then return a message as the dataset query result which can be displayed in the sub report.
Now, add a textbox to your subreport and set it to be the ReturnText field from the dataset. probably something like =FIRST(Fields!ReturnText.Value, "myDataSetName") . Make sur ethe text box is big enough to fit the whole message in.
Finally, for this subreport, add another textbox, maybe format it to look like a button, and set it action to Go To Report and choose your original report as the target, this will allow the user to click a button to get back to the original report (although the report toolbar back button might be better)
Nearly there....
Go back to the original report and in your "Update" textbox, go to properties and set the Action to Go To Report. Choose the _sub_PriceAdjust report and then add each of the 4 parameters and set their values, the first three will be the Field values from the main data set which you should be able to choose from a drop down, the final parameter (pAdjustment) will be the pPriceAdjust parameter we setup right at the start of this. There is no reason the pPriceAdjust parameter could not be called pAdjustment but I named them differently so you could see how each interacted.
Anyway, that should do it. Not pretty but it should work. There is some obvious error checking to add (is the adjustment value zero or blank for example, but I'll leave that bit to you.
To replicate your example, run the report, type 50 into the parameter and click "update" on the selected line. This should add 50 to the select price. To decrease the price back to the original amount, change the parameter to -50 and hit update.
This is completely from memory so might not be perfect but if there is something you can't figure out leave a comment and I'll refine the answer.

Related

Is there a way to use buttons in MS Access to fill in text boxes in a report?

Here's the crux of the question, I have 26 compliance queries to run, in a previous question it was suggested that I should filter a single query, or two, on a single report. I like this idea, and have rewritten the query to pull all available data from all the fields, this query works fine. The report will work fine as well, as it does with a model query that I had coded up beforehand. What I would like to do is this:
The end user is being given an interface in access that is locked down, I want them to click a button, and that button will run the query and send to the text box just the field that is called for.
I have tried doing this through VB using the where clause and aliasing the column being called, this did not work at all. I have the report currently pulling the correct data, but not displaying the dates along side it. But it is filtering correctly aside from that.
So what needs to happen is this : Button click : Query runs, and is filtered for "Compliance Issue 1" and puts the dates in "Compliance Issue 1" in the text box on the report.
Right now... I get a list of names, the correct list of names, but an empty column.
I have tried using OpenArgs, but all it did was fill in the date column with "Compliance Issue 1" not the actual data in that column.
Is what I am trying to do even possible in access, and if so does someone have a reference or suggested starting point.
My background : 6 Months of python coding, 3 months of SQL , and some limited access from 20 years ago.
As noted, using the filter of the openreport is without question the way to go (one would not write a whole bunch of different queries - you can send/have any filter for that report - you can EVEN use a sub query in the filter that you send to the report.
As for displaying values in the report that are not from "rows" of data?
There are two approaches that work quite well.
First up, is you have that launcher form. This of course allows the user to select critrea - maybe even some nice combob boxes. These selections take care and you build up the filter in code that you pass to the report.
As for text boxes to be filled out from that form and inclluded in the report?
If they are static values from the report (say filter options, or even just a notes box that you could type in some text? To display such values in textboxes on the report?
You can directly set the text box data source (in the designer) to the report propter form like this:
=(forms!MyPromptForm!notes)
So, any value you shove into text boxes on the report prompt form can thus be displayed in any text box on the report with the above type of expression. And it does not even take code to achieve this goal. So, you could say with above enter some notes into that text box, and thus on the report, whatever you typed into that text box will now show up in the report. You just drop in a text box onto the report, and set the data source of the text box to the above expression that references the form with the values we want from that form.
The next approach, and I often use this in the case that some value/expression/calculation has to occur for each row. In this case, you can use the reports on-detail format event. This allows you to run code for EACH row of data.
You are free to run ANY code in that event - and that includes after running such code to set a text box in the reports detail section.
So, say the query only had the Hotel ID (PK). This is a lame example, but you could then write this code in the on-format event of the reports detail section.
dim strSQL as string
dim rst as DAO.RecordSet
strSQL = "SELECT HotelName from tblHotels where ID = " & me.HotelID
set rst = CurrentDb.OpenRecordSet(strSQL)
me.HotelName = rst!HotelName
rst.Close
So in above, we assume that a row text box is called HotelID, and then in code we build a whole sql query from scratch, pulled the row data from a table, and then SHOVE/SET the value of the un-bound text box called hotelName.
As noted, the above is a simple example, but we are free to run any code we want, pull any data we want, and set the value of ANY text box for the given detail section ONE row of values.
So, above shows two approaches. The first approach is code free - and you can put forms! expression directly into the report, and the values from that report prompt form will thus show up directly in the report. However, if you need VBA code to run for each row, pull values, walk the dog, and THEN set a text box on that one details row of data, then you are as above shows free to write procedural code in the report that fires + runs for each row of data - and that means you can quite much do anything you want in terms of running code. I mean, even that on detail format event COULD pull values from your report prompt form, but as the 1st example shows, you can shove in forms! expression directly into a text box - and those forms! expressions can be values from a existing form that is open before the report is launched.

SSRS dropdown with progressive search

Is there a way to make a dropdown in SSRS limit what is shown as a value is typed. As it currently is it just goes to the first item starting with the letter, but in a big list, this still means a lot of scrolling to get to the desired value. This specific report is on SQL Server 2019, but if there is a way to do it for 2016 as well that would be nice to update some of the reports on older servers
Thanks
As far as I know there is no way to do this directly. However, you can do this with some compromise.
Let's say I have a long list of customers that I want to filter.
I create a dataset (dsCustomers) with a dataset query something like
SELECT * FROM customers
I have a parameter which uses this dataset as it's list of available values called pCustomer
If I want to be able to filter this list I would add a new parameter called, say, pCustSearch. This will be a simple parameter with no associated dataset. You can optionally allow NULL values.
Now I can change the dataset query for dsCustomers to be
SELECT *
FROM customers
WHERE (Customername like '%' + #pCustSearch + '%'
OR
#pCustSearch ISNULL)
NOTE: The pCustSearch parameter must be the first parameter (or at least before the pCustomer parameter)
Once you have filled in the search parameter and tab to the main customer drop down, it should filter the values that match what you have typed.

Can you rotate through visible sub reports in report builder 3?

I have one main report with several sub reports. Essentially I want to show each sub report in rotation for about 30 seconds before hiding the first one then showing the next and restarting again after all have had their time up.
Thanks
I 'think' you can do this, but there are some caveats.
You will need to setup a database table to store the current loop position, if you have several of these reports you could key it on report name for example.
(note these names are for the main report, nothing to do with the subreports)
ReportName LoopPosition LoopMax
MyMainReportA 0 3
AnotherReport 7 10
Add a dataset (lets call it dsLoop) to your main report that updates this value and returns it with something like. (Untested)
DECLARE #LoopPosition int
SELECT #LoopPosition = CASE LoopPosition WHEN LoopMax THEN 1 ELSE LoopPosition + 1 END
FROM myReportLoopTable
WHERE ReportName = 'MyMainReportA'
UPDATE myReportLoopTable Set LoopPosition = #LoopPosition WHERE ReportName = 'MyMainReportA'
SELECT #LoopPosition as LPos
This code simply adds 1 to the LoopPosition or resets it to 1 if we've hit the maximum value. It then returns this value.
Now add a parameter pLoopPos to your main report (this can be a hidden parameter) and set it default value to our new dsLoop dataset.
Now change the hidden property of each subreport to only show the subreport when Parameters!pLoopPos.Value = x where x is the order of the subreport.
Now, when the report runs it will update the loop position and get the new value. The first subreport will show as the pLoopPos will be 1 . When your report refreshes (via the AutoRfresh property) the dsLoop dataset will be reevaluated which will run the code to update the value. The pLoopPos value will increase and the next subreport will be displayed.
You may have to force the parameter to always be refreshed (from the parameter properties).
PLEASE NOTE THIS IS UNTRIED AND UNTESTED. This is just off the top of my head so I suggest a simple test report before spending too much time trying to implement it.
UPDATE: 2018-04-10 Following on from your followup question, it looks like using the parameter wont work as it does not get refreshed. However you can use the value the dsLoop returns directly. To make the change, simply swap out
Parameters!pLoopPos.Value with =First(Fields!LPos.Value, "dsLoop")
Note: I modified the dsLoop query slightly to give the final result a name (LPos).
You should now be able to delete the parameter as its no longer used.

Report Builder 3.0 - permit user to add data in after report generated

Using Report Builder 3.0 against cubes which are produced overnight.
The report I'm designing is used to archive or transfer (physical) files for patients. Users run the report, print it & then attach it to files that are then sent to a central area which will archive/send the files on.
The report has a number of parameters which is designed to return a single patient. This all works fine.
One of the parameters (#prmReason) is a single choice on what is to happen to the files, eg, "Transfer" (transfer files to another office), "Archive - closed", "Archive - deceased", "Archive - excess" (office space is limited, so staff archive off 'older' files).
One of the fields returned is CloseReason. This field always has a value. If the field is empty in the database (as the client hasn't closed), then it will contain the value: "Unknown".
This field (amongst others) are either displayed or hidden, depending on #prmReason. Again - all working without a problem.
Now for the tricky bit.
If the #prmReason = "Archive - closed" or "Archive - deceased" then the report will display CloseReason.
The problem is if CloseReason = "Unknown" then I need to know the why the file is closed & display it on the report.
I want users to be able to choose a value from a list of closure reasons. I then want the choice to be displayed on the report. Obviously if there is a genuine reason then display this value.
So the effect I'm after is:
User selects parameters & runs report.
Report then checks to see why report is being run (eg #prmReason).
If #prmReason =("Archive - closed" OR "Archive - deceased") AND CloseReason = "Unknown"
Then somehow produce a list of CloseReasons that the user can select. This value is then displayed on the report.
I can even cope with it being a free text field. Just something so that the central area can update the database if necessary & save a phone call/email etc.
(Yes, I realise that I can have the list as a series of tickboxes that the user ticks after the report is printed, but this would be a useful ability in other reports).
EDIT: empty value of CloseReasons conflicted with stackoverflow formatting (sorry didn't review post properly). Value is actually less then symbol then the word Unknown and then greater than symbol. It doesn't really affect the problem
You could add an additional hidden parameter.
If this parameter is not set then display an small table on your report that has a list of CloseReasons.
You then set table cell's action property to open the a report, choose your existing report as the report to open but this time you can pass a value for the final parameter, which, as well as displaying the Close reason in your report, would also hide the close reason choices table described above.
UPDATE To make clear more clear.
The following is based on the Northwind sample database. I have a shared data source pointing to this database.
Create new report.
Add a data source pointing to the shared Northwind data source
Add a new data set pointing to the data source above with the following query
SELECT
EmployeeID,
FirstName, LastName, Address, City, Country, Title, Notes
FROM Employees
WHERE EmployeeID = #EmployeeID
Add some of the fields to the report to show some basic info.
We now have a simple report with a single parameter #EmployeeID
Next we want to show some actions for each employee. For flexibility, I'm making this list dynamic based on the employee's Country. This list could be static.
Create a new dataset dsActions with the following query
DECLARE #actions TABLE(ActionID int, ActionLabel varchar(20))
-- Get employees country
DECLARE #Country varchar(20) = (SELECT Country FROM Employees WHERE EmployeeID = #EmployeeID)
IF #Country = 'UK'
BEGIN
INSERT INTO #actions VALUES
(1,'Sack them'),
(2,'Buy them a pint'),
(3,'Promote')
END
ELSE
BEGIN
INSERT INTO #actions VALUES
(1,'Fire them'),
(2,'High 5 them'),
(3,'Ask them to run for office')
END
SELECT * FROM #actions
Add a table to the report to show these values.
At the moment my design looks like this. (All the expressions are simple fields from the first dataset to show the employee details, nothing special)
And when I run it I get this.
OK, now all the basics are done, we need to be able to call this report again, but with an action already chosen. We'll make the actions table clickable and pass the action's label to the report.
It's the same report, we will only ever have a single report.
First, add a new parameter called action to the report and make it hidden. Add a default value of 'noaction'.
Next we want to only show our actions table if the action parameter is set to 'noaction'. To do this, set the Hidden property of the action table (tablix) to the following
=Parameters!action.Value <> "noaction"
Next we want to add a text box that displays the result action parameter, but only when the action parameter is not noaction.
So add a text, set it's expression to =Parameters!action.Value and the hidden property to =Parameters!action.Value = "noaction"
Finally, we need to make our actions list call our report but with a specific action. To do this we need to modify the actions table.
First save the report, whatever name you choose is the name you will select as the target report as the report will call itself.
Right-click the cell that contains the ActionLabel and go to the text box properties.
Select the Action tab and then choose "Go to report". Choose the name of the report you are currently working on (this actual report as the report will call itself).
Set EmployeeID parameter to [#EmployeeID] and the action parameter to [ActionLabel]
I've used the label for simplicity but you could pass the ActionID as long as you account for this in the text box that displays the action.
Optionally you could format the text so it looks like a link,
The final design and action/parameter setup looks like this
When I first run the report I get the following...
As soon as I click one of the actions, I then get this...
Hopefully that's clear now.

SSRS report pass multiple VALUES to drill through report parameter

I created a report with 5 fields in a hierarchical order:
Order Date
Time of Day (AM/PM)
Parent Name (aka customer)
Product Line
BIC Part Number (aka Item)
Each field expands down to the next level, so order date expands to time of day, etc.
I want to create a drill through report so that the user can click on each level of the hierarchy and see the detail.
This works fine at the lowest level - Item - because only 1 values from each field has to be passed to the drill through report parameter. However, when I try, for example, to drill through based on Product Line, there will usually be 3 or 4 Items within this product line. In the Go To action, I have the drill through parameter "bic_part" set to the main report FIELD value "BIC Part Number".
I have the tablix on the drill through report set where "BIC Part Number" IN [#bic_part].
I just want to be clear, I am passing a set of report field values to the drill through report parameter, not parameter to parameter.
I have tried using expressions with =Split(Join(field value),","),",") and all variations on that. I can't seem to get the child report filters to accept multiple values from the BIC Part Number field from the parent report.
I also tried omitting the BIC Part Number value in the go to report section, but it would not let me.
All of the parameters in the child report are set to accept multiple values. My data source for both reports is the same stored proc, so I can add a query filter. I would appreciate any help.
I think each sub report link needs to be slightly different.
In the subreport, each parameter needs to accept null and your query needs to look for
(FieldName = #FieldNameParameter or #FieldNameParameter is null)
This will allow you to pass the lowest possible solid value, then null for all child values.
If we're looking at the Parent_Number level, on that subreport link you would pass Fields!Parent_Number.Value and then Nothing for each of the lower parameters (Product_Line, BIC_Part_Number).
This will allow you to filter on the lower common denominator in your sub report - Part_Number for this link, Product_Line for the next one down, etc.
I've used this logic in reports before, so it does work. Let me know if my explanation needs clarification - it's Friday afternoon..