D J Horton Consulting Ltd

Personal reference to useful tips and tricks for SQL Server, SQL Server Reporting Services and Crystal Reports.



My alternative to scraps of paper lying about.



Others may find bits of it useful!








Thursday, 6 October 2011

Using Count function on a uniqueidentifier field - SQL

SELECT COUNT(D.DOCUMENTID) AS DocCount, P.TITLE
FROM DOCUMENT AS D inner join
PROJECT AS P ON D.PROJECTID = P.PROJECTID
GROUP BY P.PROJECTID, P.TITLE

When running this query I encountered the following error:

Msg 409, Level 16, State 2, Line 1
The count aggregate operation cannot take a uniqueidentifier data type as an argument.


   
To avoid this error when trying to Count a uniqueidetifier field you have to CAST it into a char :
 
SELECT COUNT(CAST(D.DOCUMENTID AS char(36))) AS DocCount, P.TITLE
FROM DOCUMENT AS D inner join
PROJECT AS P ON D.PROJECTID = P.PROJECTID
GROUP BY P.PROJECTID, P.TITLE

Thursday, 29 September 2011

A3 Landscape dashboard layout - SSRS

For A3 Landscape dashboard style settings:

Report Properties:
Grid Spacing  0.2cm

InteractiveSize
    Width  42cm
    Height  0cm

Margin all 0.5cm

PageSize
    Width  42cm
    Height  29.7cm

Body Properties:
Size
    Width  41cm
    Height  28.7cm
 

Monday, 5 September 2011

Resolving Common Connectivity Issues

Useful link to resolving common connectivity issues. Applies to SSAS but also proves to be of use with IIS, SSRS & SQL Server.

http://msdn.microsoft.com/en-us/library/cc917670.aspx

Tuesday, 16 August 2011

Performance of SQL commands and subreports in Crysal Reports - CR

I've been recently attempting to imrpove the performance of a number of 'legacy' Crystal Reports. One in question contained approximately 7 subreports with the main report returning 300+ records. I saw this an ideal candidate for using solely a SQL command.

I'd re-written the Crystal using said SQL command and then compared the performance of both existing subreport and new SQL command versions using SQL Server Profiler.

The first image shows the existing subreport version:


The second shows the SQL command version:

I was surprised to see the values returned by the SQL command version which seemed vastly larger than the sum of all the 'subreport' performance values. But, on closer inspection I realised that the subreport was only returning data for the first page in Crystal Reports whereas the SQL version was gleaning all the database info in 1 go.

The below image shows the performance of the subreport version when the user refreshes the report on page one and subsequently moves to page two (page one returns two main report rows whereas page report returns three).

As this report contains over 70 pages it is plain to see that using the subreport version the database would be queried multiple times and incur all the related network traffic. It is thus beneficial to go with the SQL command version (as originally expected!). Summing up all the CPU and read and writes also confirms this.

One concern that I've been unable to resolve is that Crystal Report seems to create two SQL batches when using a SQL command thus doubling the performance overheads. The same query when run in SQL Server Management Studio records only 1 SQL batch as expected. I need to look into this as I'm not fully sure why this is occuring.

Friday, 3 June 2011

Using SQL commands, parameters and subreports - CR

My report contains a number of subreports, each comprising a SQL command and using a parameter value passed from the main report.

1) Set up the main report parameter, in this instance called ?School















2) Add a subreport, Add Command with the Where clause as follows:

WHERE (School.SchoolKey = {?School})














3) For the Parameter list, Click Create:

Parameter Name = School
Value Type = Number
















It will then prompt for a parameter value, enter 1 (anything will suffice at this stage)

NOTE: When the database field is a uniqueidentifier, use 'String' type and for the prompt use a value in the uniqueidenfier format: {29D2B899-393A-4592-9B00-D289884A1F94}

4) Back in the main report, right click the subreport and Change Subreport Links:

Available Fields = ?School
Subreport parameter field to use = ?School (make sure to select the user-generated one and not the automatically generated one named similar to ?PM-?School)















5) Voila! Main report parameters should now be passed to SQL Commands in subreports.

Wednesday, 16 March 2011

Display parameter Label field - SSRS

I was familiar with displaying a parameter's value field by using the expression:
 =Parameters!parameterfield.Value

But in many cases this value will be a key field and pointless to display. The 'Label' field is required and is obtained by simply changing the expression to:
=Parameters!parameterfield.Label

Simple and obvious really!

Wednesday, 9 March 2011

Return a random row - SQL

Instead of using the RAND() function which I believe is not truly random since using the same seed value results in the same output:



Whereas, CHECKSUM(NEWID()) would work:


and can thus be used to return a random row:


SELECT TOP(1) School.SchoolNameFROM School
ORDER BY CHECKSUM(NEWID());

Tuesday, 15 February 2011

Nob Hill Software - Useful information we can get out of a query execution

Here's a guest article by Nob Hill Software. http://www.nobhillsoft.com/


Much has been written about Query Execution Plans (we’ll call them QEPs), and how they can be used for analyzing how SQL Server interprets your TSQL code and what it does behind the scenes –
information you can use to do such things as find bottlenecks, build indexes where they might help, and generally improve the performance of your code.


Well, we have found more uses for it. There is more information in the QEP, information that’s not typically used, yet is highly useful and very easy to retrieve:

1. IS YOUR CODE BROKEN?

TSQL code can get ‘broken’ all the time. You might be referencing tables or columns that don’t exist.
They might have even existed at the time you wrote the procedure, but have been removed since, leaving your procedure ‘broken’ - It will raise an error next time its executed. How many of those do YOU have in your database?

Now, if a code is broken, SQL Server will let you know about that when attempting to retrieve its execution plan. Strictly speaking, this is not QEP information. Its information you will get while trying to get the QEP. And that is not the only way to get that information. But it’s the easiest.


2. WHAT ENTITIES ARE USED IN FOR WHAT OPERATION?

Among all the logical and physical operations, and effects on memory etc, QEP also contains the very basic information of what entities it is working with, and what it does on such entities. This information can be then used to build a basic ‘browser database’, which you can use to answer questions like: which code inserts to this table? I got data missing… which procedure removes records from here?

In order to get any SQL’s execution plan in SQL Server, all you need to do is:


set SHOWPLAN_ALL on
write your SQL here
set SHOWPLAN_ALL on

If you get an error, this means the stored procedure is broken, and the error would say why.
Otherwise, you can get the execution plan in a tabular format, and retrieve the specific entities used from it.


We put this functionality into one of our freebie products, Diana Lite. You can build the full ‘browser database’ out of the collection of any database’s SQL Code, then easily filter it and get to whatever you are looking for:





Sweet, Huh?
 
http://www.nobhillsoft.com/Freebies.aspx

Wednesday, 19 January 2011

FInd current financial year start and end dates - CR

To find the start date and finish date of the current financial year for subsequent use in various calculations:

Start of year formula:

Local Datetimevar dates := CURRENTDATETIME();
Local Datetimevar startfinancialyear;

IF MONTH(dates) IN [1,2,3]
THEN startfinancialyear := (DATESERIAL (YEAR(dates)-1,4,1))
ELSE startfinancialyear := (DATESERIAL (YEAR(dates),4,1));


End of year formula:
 
Local Datetimevar dates := CURRENTDATETIME();
Local Datetimevar endfinancialyear;

IF MONTH(dates) IN [1,2,3]
THEN endfinancialyear := (DATESERIAL (YEAR(dates),3,31))
ELSE endfinancialyear := (DATESERIAL (YEAR(dates)+1,3,31));


Alteration: The End of year formula gets the last day of the financial year, i.e. 31st March. However, it returns the value for the very start of the day (31/03/xxxx 00:00:00) which when incorporated into a selection formula could potential lead to records logged during that final day being excluded.

A correction would be:

End of year formula (correction):
 
Local Datetimevar dates := CURRENTDATETIME();
Local Datetimevar endfinancialyear;

IF MONTH(dates) IN [1,2,3]
THEN endfinancialyear := DATEADD("s" , -1, (DATESERIAL (YEAR(dates),4,1)))
ELSE endfinancialyear := DATEADD("s" , -1, (DATESERIAL (YEAR(dates)+1,4,1)));

Thus, returning a value of "31/03/xxxx 23:59:59"





(Currently set up for use in the UK)


Tuesday, 4 January 2011

Using the EXCEPT clause wrapped in a CTE - SQL

--
--example EXCEPT clause wrapped in CTE
--
WITH RogueEstab
AS
(
SELECT EstablishmentID FROM Establishment
EXCEPT
SELECT JobLog_EstablishmentID FROM JobLog
)
SELECT RE.EstablishmentID, E.EstablishmentName FROM RogueEstab AS RE
INNER JOIN Establishment AS E
ON RE.EstablishmentID = E.EstablishmentID

Using the EXCEPT clause - SQL

--
--example EXCEPT clause....lists EstablishmentID without corresponding Jobs
--
SELECT EstablishmentID FROM Establishment
EXCEPT
SELECT JobLog_EstablishmentID FROM JobLog
ORDER BY EstablishmentID

Using the OVER clause - SQL

--
--using OVER clause to get count of SubTypes
--
SELECT E.EstablishmentName, S.JobSubTypeDescription
,COUNT(*) OVER(PARTITION BY S.JobSubTypeDescription) AS nums
FROM Establishment AS E LEFT OUTER JOIN
JobLog AS J ON E.EstablishmentID=J.JobLog_EstablishmentID INNER JOIN
JobSubType AS S ON J.JobLog_JobSubTypeID=S.JobSubTypeID
ORDER BY E.EstablishmentName