With Reporting Services is number formatting so easy. You can continue with our series and get report from here, or just open your report and follow bellow instructions. There are 2 basic places in designer surface where to format figures in your report Tablix.
Through Tablix Text Box Properties
Properties Pane
Tip: if you would like to format more text boxes in Tablix you can do it in few ways.
Select text boxes you would like to format by clicking mouse cursor holding Left shift and change formatting in Properties Pane. (this will work in case that all text boxes would have the same formatting, if one text box format differs from others you will not be allowed to change the format).
You can change formatting in one text box and by copy paste action to other textboxes, formats are transferred.
Download report and open it in a texts editor and replace formatting tags
Let’s look on the report we created in post SSRS Tablix – repeating header. We would like to format Sum Sales Amount column with currency.
Picture 1 Sales Report
Go to text box with Sum Sales Amount value. Choose for example the one from EnglishCountryName group, right click and select Text Box Properties from popup menu.
Picture 2 Textbox Properties
Text Box Properties window is opened, and you can set Currency formatting options. Click on Currency category and choose format you would like to apply. On picture bellow you can see that you have many options to set currency format: how many decimal places, if use 1000 separator, how to display negative numbers which currency symbol to display and where, etc. Regional setting of machine where Reporting Services are installed has impact on default settings in Text Box Properties window. Reporting Services supports regional formatting in different regional environments. For our report I left the default English settings.
Picture 3 Textbox Properties – Number currency format
After formatting the rest of text boxes with Sum Sales Amount you can see formatted report bellow.
Picture 4 Sales report – currency format
In Properties Pane, Number section, Format property you can find currency formatting we set.
Picture 5 Properties Pane – Number format
In other posts I will describe other scenarios and approaches to format data in reports.
When I started developing with Reporting Services I was confused when I would like to make Tablix header repeating on each page. I tried to manage it through Tablix properties and Row headers or Column headers section. But as states on MSDN in case of static groups in Tablix you should use another approach then in case of non-static members. Since I was working mainly with Tablix component, I worked with static members. So, I had to apply approach described in this post. For this scenario I will use report from post Grouping Tablix.
Picture 1 Grouped Sales Report
Open the report and in design mode select Tablix, right click and select Tablix Properties from popup menu. In the dialog box you can see menu saying Repeat header rows on each page, Keep header visible while scrolling and the same menu for columns. When you check this checked-boxes in Row Headers or Columns Headers section and run the report again nothing happened. This setting would work in case of Matrix component. Because there is no need to have static groups. In case of Tablix report, headers are static groups. So, let’s close properties window and click on the Tablix again.
Picture 2 Tablix Properties
At the bottom of designer or studio surface, in the Grouping pane, there is an arrow, on the right side and by clicking on it you can enable Advanced Mode (picture below). After enabling this feature you can see static groups in Grouping pane. When you click for example on first static group Row Groups panel you can see that Last Name text box on the left-top corner of the Tablix is selected.
Picture 3 Grouping Pane
Having Static Last Name group selected, you can see its properties in the Property pane (picture below). We need to set FixedData, KeepWithGroup and RepeatOnNewPage attribute as on picture below. FixedData = True, KeepWithGroup = After, RepeatOnNewPage=True.
Picture 4 Properties Pane
Run report again and you can see header repeating on each page and staying on top when scrolling the report page. And that’s it. In next posts I will try on repeating groups in more details.
Since logging is fundamental functionality for many SQL applications, I still ask myself what the best approach is to make SQL log for your application. In lots of my solutions I got with SQL log table approach. But there could be other ways how to implement SQL logging mechanisms. I decided to use Extended Events functionality to implement such a solution. This is powerful feature of SQL server. There are many examples on internet web sites where you can find this functionality was implemented mainly for maintenance purposes or SQL server counters monitoring. But let’s try to find another usage for this feature.
Problem
Let’s develop error log solution for simple insert query. For our solution we will use extended events.
You can create extended events in SQL Management Studio -> Management->Extended Events section as you can see on picture bellow, in this post I will use T-SQL scripts.
Picture 1 Extended Events
In short:
Create testing database
Create log table
Create extended event session
Start extended event session
Simulate event which trigger log message
Get data from extended event
Put data into log table
At first, we prepare database with log table.
CREATE DATABASE LogTest
GO
USE LogTest
GO
IF OBJECT_ID('dbo.LogData') IS NULL
CREATE TABLE dbo.LogData
(sql_text NVARCHAR(1000),[log_datetime] DATETIME,[message] NVARCHAR(100))
The next step is to create extended event session. I named it LogTestSession. Since I would like to monitor error messages I will add object sqlserver.error_reported. It handles events connected to error messages triggered on the server. In Action section there are listed attributes we want to get from extended events. Where clause contains filters to our database (we get ID of our database) and then put it to this predicate (Because we would like to test it only on our database) Error number = 50000 means that we would like to check only user messages. As you can see there are many ways how to configure behaviour of extended events. There is not necessary to use filter and you can monitor all databases on the server and error messages. As target we use Ring buffer, it means that data will be written to memory. There is possibility to redirect extended event output to other destinations. I will not describe all possibilities in this post, more info can be found here: https://bit.ly/2JEVDcV.
The last attribute, I used in this solution is MAX_DISPATCH_LATENCY = { seconds SECONDS | INFINITE } and here is definition directly from Microsoft sites https://bit.ly/2HCIHSD. Specifies the amount of time that events will be buffered in memory before being dispatched to event session targets. By default, this value is set to 30 seconds.
Bellow is T-SQL batch for creating extended event session.
CREATE EVENT SESSION LogTestSession ON SERVER
ADD EVENT sqlserver.error_reported -- ,
(
ACTION (sqlserver.sql_text, sqlserver.tsql_stack, sqlserver.database_id,sqlserver.username)
WHERE sqlserver.database_id = 33 AND [error_number]=50000 /*Filter error no or db number*/
)
ADD TARGET package0.ring_buffer
(SET max_memory = 4096
)
WITH (max_dispatch_latency = 1 seconds)
In next step we start extended events. Since that time, we can test our mechanism.
ALTER EVENT SESSION LogTestSession ON SERVER
STATE = START
Now we get data from extended events. There are few useful catalos in SQL server. In the script bellow we get data from tables containing user messages and stage them into temporary table like XML.
IF OBJECT_ID('tempdb.dbo.#LogData') IS NOT NULL
DROP TABLE #LogData;
SELECT
CAST(LocksAcquired.TargetXml AS XML) AS XMLData
INTO
#LogData
FROM
(
SELECT
CAST(t.target_data AS XML) AS TargetXml
FROM
sys.dm_xe_session_targets AS t
JOIN sys.dm_xe_sessions AS s
ON s.address = t.event_session_address
WHERE
s.name = 'LogTestSession'
)
AS LocksAcquired;
Now let’s parse our data to our LOG table. In next step we can create one procedure from these two queries. IT would fit better in scenarios of next posts.
INSERT INTO dbo.LogData (sql_text ,[log_datetime] ,[message] )
SELECT
T.XMLData.value('(action[@name="sql_text"])[1]',
'varchar(1000)' ) AS [SqlText],
T.XMLData.value('(@timestamp)[1]',
'datetime' ) AS [OccurredDtTm],
T.XMLData.value('(data[@name="message"])[1]',
'varchar(60)' ) AS [Message]
FROM
#LogData
CROSS APPLY XMLData.nodes('/RingBufferTarget/event[@name="error_reported"]') AS T(XMLData);
Look to our log table and voila. Log messages are there.
SELECT * FROM dbo.LogData
Picture 2 Result
Clean up our solution.
IF EXISTS (SELECT *
FROM sys.server_event_sessions
WHERE name = 'LogTestSession')
BEGIN
DROP EVENT SESSION LogTestSession
ON SERVER;
END
In this post I demonstrate how Extended Events could be used for logging purposes. Be aware that this approach does not come with real-time solution but with the asynchronous one. So, it cannot fit to every solution. On the other hand Extended Events are not in scope of transaction. Furthermore, here raise other questions which could be answered in other posts.
Handling error messages within transactions
What about extended events and their performance?
Ring buffer is still increasing, do we have solution to clean it up?
It could be interesting to compare this solution with classic approach within transaction scope
Whatever idea you get….
Stay tuned, stay strong
PS: if you would like to play, you can download the whole script here ext_events_log.