I'm looking for a way to get versioning informations out of my SSRS reports. I have several environments and would like to be able to compare which report version is deployed on these environments. In SSIS this is very easy because each SSIS package gets a new version when it was modified and safed. Is there something similiar with the reports ?
Unfortunately there currently is no built-in functionality similar to a dll assembly version for RDL files.
The only way to get some kind of version information is to query the last modified date of the RDL file on the server via C# or VB.Net. You could do this using the ReportingServices webservice.
You could also implement a custom function which updates some field in your database to the current date each time the RDL file modified.
The problem with all the file modified information: You still don't know which version is on which server, you just know when it was uploaded/modified.
See the following pages for some more information - unfortunately no solution:
SSRS 2005 Can I dynamically determine when .rdl file was last modified
.RDL "Version" properties like in ".DTSX" files
In my reports, I create a variable named Version and make it a string data type (and move it to the top of the variable list). Every time I change a report, I update the Version variable based on Semantic Versioning.
Then, I can query my Report Server and look at the Parameter field of the ExecutionLog table and I can see what version was run. Technically I take care of all of this in an SSIS job that writes to another table, but that's a little outside the scope here.
There still seems to be no good solution.
If you create a hidden Parameter "Version" with a default value you could use a build Task to modify its value in the .rdl file, e.g. the revision part with the source control changeset number.
Sadly you may need another visual Studio Project to place this build task since the reporting project type seems not capable.
You may also create inline code or an assembly that may do some lookup.
Cheap suboptimal alternative:
Use the last modified date form the report database:
Select
Name,
Path,
CreationDate,
ModifiedDate,
ModUser.UserName AS ModUser,
CAST(catalog.parameter as xml).value(/Parameters[1]/Parameter[Name="Version"][1]/Values[1]/Value[1]','NVARCHAR(20)') as Version
FROM Reportserver.dbo.Catalog
INNER JOIN ReportServer.dbo.Users ModUser on Moduser.UserID = ModifiedByID
WHERE Type = 2
and convert the date to a revision number...
Doesen't help with versions across different server instances though.
The Report Server dbo.Catalog table has both CreationDate and ModifiedDate.
As part of an investigation I put together a query to list out the queries in RDL files and perform a simple CHECKSUM on that to facilitate checking for drift.
You can of course do the same on the whole of Content field much more simply, or do a better job of opening the XML using real xml processing.
Hope it is helpful;
DECLARE #reftextstart VARCHAR(255);
DECLARE #reftextend VARCHAR(255);
SELECT #reftextstart = '%<CommandText>%';
SELECT #reftextend = '</CommandText>';
SELECT SQ2.Path,
SQ2.Name,
SQ2.CreationDate,
SQ2.ModifiedDate,
ReportQuery,
CHECKSUM(ReportQuery) ReportQueryChecksum
FROM
(
SELECT SQ.Path,
SQ.Name,
SQ.CreationDate,
SQ.ModifiedDate,
CASE PATINDEX(#reftextstart, Report)
WHEN 0 THEN
N''
ELSE
SUBSTRING(
Report,
PATINDEX(#reftextstart, Report) + LEN(#reftextstart) - 2,
CHARINDEX(
#reftextend,
SUBSTRING(
Report,
PATINDEX(#reftextstart, Report) + LEN(#reftextstart) - 2,
1024
)
) - 1
)
END ReportQuery
FROM
(
SELECT TOP 1000
[Path],
[Name],
[CreationDate],
[ModifiedDate],
[ExecutionTime],
CONVERT(VARCHAR(MAX), CONVERT(VARBINARY(MAX), Content)) Report
FROM [ReportServer].[dbo].[Catalog]
WHERE Name IN ( N'Report1', N'Report2' )
) SQ
) SQ2
ORDER BY [Path],
Name;
I tried this solution for my customers:
Open the .rdl file with notepad and add a comment in the first line and save it, like:
<?xml version="1.0" encoding="utf-8"?>
<!--
=============================================
Author: My Name (My Company)
CHANGE date: Release Date
Description: Short description
Current Version: Ver x.x.x
Vx.x.x: Version change history
=============================================
-->
<Report MustUnderstand="df" xmlns=...
I hope it helps others
Related
This question already has an answer here:
Dynamic parameter of table name in Jasper [duplicate]
(1 answer)
Closed 3 years ago.
I have this problem with the JasperServer report I'm trying to create:
I have several db tables, named using a name and a date like this:
TABLE_NAME_YYYYMMDD
I want to be able to choose (and do a select from) the table which corresponds to the date submitted by the user from an ordinary Date input control.
I've tried creating a variable (called TABLE_NAME) which uses Java expressions for parsing the date like:
"MY_TABLE_" + new SimpleDateFormat("yyyyMMdd").format($P{RUN_DATE})
and when I print the value of the variable in the report it looks correct. But then I tried using that variable name in the SQL query like:
SELECT column1,column2.. from $V{TABLE_NAME}
but when I tried running the report in Jaspersoft Studio I got this Exception:
net.sf.jasperreports.engine.JRException: net.sf.jasperreports.engine.JRException: Error executing SQL statement for: my_report_x.
at com.jaspersoft.studio.editor.preview.view.control.ReportControler.fillReport(ReportControler.java:511)
at com.jaspersoft.studio.editor.preview.view.control.ReportControler.access$20(ReportControler.java:486)
So it doesn't seem to be working.
I read about the case when the whole table name can be specified in a parameter, and you're supposed to use:
$P!{tableName}
First I tried using that '!' with the variable name like:
..from $V!{TABLE_NAME}
but I got the same Exception.
Then I tried creating a new parameter instead, where "Is For Prompting" is Not checked, and as default value expression I put the same expression as I used in my variable:
"MY_TABLE_" + new SimpleDateFormat("yyyyMMdd").format($P{RUN_DATE})
but I still get the same error when I try to run the report in Jaspersoft Studio.
Does anyone know if there is a way to solve this? -Preferably a way that doesn't take several days to implement since I don't have that time.
I'm using Jaspersoft Studio 6.1.1.final and running the reports in JasperServer 5.5.0.
You should be able to get this to work by wrapping the whole of your FROM expression in the parameter e.g.
<parameter name="pTableName" class="java.lang.String">
<defaultValueExpression><![CDATA["from MY_TABLE_" + new SimpleDateFormat("yyyyMMdd").format($P{RUN_DATE})]]></defaultValueExpression>
</parameter>
And then using this in your SQL as a string literal:
SELECT column1,column2
$P!{pTableName}
WHERE 1 = 1
I just found out what I did wrong.
I admit it was rather stupid, but I only tried running the report in the Preview mode in Jaspersoft Studio. That's when I got the SQL error.
But I assume that the Preview mode does not support dynamic decisions about which table to read from, because when I ignored the Preview errors and published the report to JasperServer, I actually could run it there!
I ended up using the $P!{TABLE_NAME} parameter where the value is what I tried earlier:
"MY_TABLE_" + new SimpleDateFormat("yyyyMMdd").format($P{RUN_DATE})
I can print as much as possible of my SQL here (meaning that I have to replace names since this is a work report) if you want to see it:
select c.column1,c.column2, h.column3 from $P!{TABLE_NAME} h, TABLE2 i, TABLE3 p, TABLE4 ca, TABLE5 c
where h.P_ID = p.P_ID and h.A_ID = ca.A_ID and ca.C_ID = c.C_ID and ca.SOME_VALUE = 1 and ca.OTHER_VALUE = 1
and i.I_ID=h.I_ID
and i.OTHER_ID=1
and h.VALUE_X > 0
order by c.VALUE_Y
So my advice to others who create Jasper reports is not to let yourselves get fooled by the fact that some things don't work in Preview mode. -That might just be the "preview limitations".
I have a Form which will help me to filter out the records I want for my Report. The button will open the Report On Click.
This is the code in the button:
Private Sub Open_OEE_Click()
DoCmd.OpenReport "OEE_Report", acViewReport, , , acWindowNormal
End Sub
I keep getting the error:
I also have placed the query in my report under the Record Source as:
SELECT * FROM 3_OEE WHERE ((([3_OEE].RecordID)=Forms![3_OEE_Report]!cboRecordID) And (([3_OEE].Date_Recorded)=DateValue(Forms![3_OEE_Report]!Date_Recorded)) And (([3_OEE].MC_No)=Forms![3_OEE_Report]!cboMCNo) And (([3_OEE].Product)=Forms![3_OEE_Report]!cboProduct));
I want to search based on one criteria (text box or combo box) and not all four at once.
Am I missing out something?
MS-Access does tend to go a bit overboard with the brackets. Make the report's Record Source a bit easier to read by trimming out the unnecessary ones. You also need to get your date criterion in the right format - Access always uses US formatting in SQL queries and needs # signs around the date:
SELECT * FROM 3_OEE
WHERE [3_OEE].RecordID = Forms![3_OEE_Report]!cboRecordID
And [3_OEE].Date_Recorded = Format(Forms![3_OEE_Report]!Date_Recorded, "\#mm/dd/yyyy\#")
And [3_OEE].MC_No = Forms![3_OEE_Report]!cboMCNo
And [3_OEE].Product = Forms![3_OEE_Report]!cboProduct;
I would also suggest creating a named query for this and setting the report's Record Source to the named query. You can then test the query in isolation without having to run the report (but make sure the Form is open and the relevant controls are populated).
I asked for help from another source.
Answer to Question
I Have created a stored procedure:
#DeviceID nvarchar(20) =''
WITH EXECUTE AS CALLER
AS
SELECT
amd.BRANDID,
amd.DEVICEID
FROM AMDEVICETABLE amd
where
left(amd.Deviceid,len(#DeviceID)) in (#DeviceID)
The length of amd.Deviceid is about 15 characters
In Visual Studio I create a parameter #DeviceID and when I am entering e.g ABCDE ( the first 5 characters from Deviceid) everything is working perfect.
the problem is that I want to put multiple values like
jhmcl*, jhmgd*.
So I created my own little version of your report and I believe the problem is your LEN() function. I'm surprised it doesn't return an error because it errors out in Report Builder for SQL Server 2014(simple version of SSRS). I would test what your LEN(#DeviceID) is returning. I would bet it's not returning the correct value. Instead you might try this to cover every possible pattern. I don't know how it will work performance wise.
SELECT DeviceID
FROM YourTable
WHERE LEN(DeviceID,1) IN (#DeviceID)
OR LEN(DeviceID,2) IN (#DeviceID)
OR LEN(DeviceID,3) IN (#DeviceID)
..
OR LEN(DeviceID,15),IN(#DeviceID)
XML Tree is -
<OrderLine>
<Item>ABC</Item>
<Lot>
<Serial>SR1</Serial>
<Quantity>1</Quantity>
</Lot>
<Lot>
<Serial>SR1</Serial>
<Quantity>1</Quantity>
</Lot>
</OrderLine>
While trying to parse this tree for element values using openxml in SQL Server 2005 (stored procedure) only one is read.
Here's the code -
select item, lots
from openxml(#intDataAreaRoot, 'OrderLine', 2)
with ( item nvarchar(31) 'Item',
lots xml 'Lot'
)
I use this to declare a cursor and then parse & process as many lines as there may be in the tree. But each "fetch" brings only one "Lot" node. I need to process all "Lot" nodes under the "OrderLine" node.
Appreciate any help.
Try something like this, using the native XQuery support in SQL Server 2005:
DECLARE #intDataAreaRoot XML = '<OrderLine>
<Item>ABC</Item>
<Lot>
<Serial>SR1</Serial>
<Quantity>1</Quantity>
</Lot>
<Lot>
<Serial>SR2</Serial>
<Quantity>21</Quantity>
</Lot>
</OrderLine>'
SELECT
Item = #intDataAreaRoot.value('(/OrderLine/Item)[1]', 'varchar(25)'),
xc.value('(Serial)[1]', 'varchar(20)'),
xc.value('(Quantity)[1]', 'int')
FROM
#intDataAreaRoot.nodes('/OrderLine/Lot') AS XT(XC)
This gives me an output of :
Item (No column name) (No column name)
---------------------------------------------
ABC SR1 1
ABC SR2 21
In Crystal reports, you can define default values for the report parameters.
For example, I might have a date range and set a default start of 12/01/2008 and a default end of 12/31/2008.
Is it possible to modify these defaults at runtime? For example:
1 - Default to the first and last days of the current month?
2 - Default to the first and last days of a proprietary company fiscal calendar? (i.e., look it up in a database)
3 - First & Last days of the current year?
You get the point. Is this possible? I'd even be open to a solution that involved running an external application to reach into the reports and modify them, if anyone knows how to do that.
Edit:
To answer the question posed by Philippe Grondier, most of these reports are run from inside an application. I was hoping for something simpler than manipulating the crystal object at runtime; I have my hands full right now with figuring out other parts of that API. I might take a look in the future, though.
Are you planning to run your crystal report from the crystal reports interface or as an add-in embedded in another program (you can for example use the Crystal Reports ActiveX Designer Runtime Support - craxdrt.dll - in VB code) ? In this last case, it is possible to manipulate every object of the report before launching it. Objects such as parameters can then be updated according to your needs.
As a simple example of such runtime update, my report printing routine will allways check if there is a field named "printedBy" in the report. In case this field is found, its value will be settled to the the domain name of the user that requests the report and will be printed out.
At an higher level, you can even reshape the report SQL string to add specific filters that can be inherited from your code. By doing so you might not even need parameters anymore: let your code add the filtering values 'on the fly'
EDIT: some code examples:
(m_rapport is a CRAXDRT.report object, ActiveSession is my current session object)
If m_rapport.ParameterFields.Count > 0 Then
For i = 1 To m_rapport.ParameterFields.Count
If m_rapport.ParameterFields(i).Name = "{?PUB_DateDebutPeriode}" Then
m_rapport.ParameterFields(i).AddCurrentValue CDate(DateValue(sessionActive.dateDebutPeriode))
End If
If m_rapport.ParameterFields(i).Name = "{?PUB_DateFinPeriode}" Then
m_rapport.ParameterFields(i).AddCurrentValue CDate(DateValue(sessionActive.dateFinPeriode))
End If
If m_rapport.ParameterFields(i).Name = "{?PUB_id_Personne}" Then
m_rapport.ParameterFields(i).AddCurrentValue StringFromGUID(clientActif.id_Personne)
End If
Next i
Endif
I also have another function to change report's datasource at runtime, so that reports can be executed on different servers/locations.
Read my posting Crystal Reports: Named-Date-Range Parameters. Maybe you'll be able to leverage this technique for your purposes.