Is there a simple way to view the SQL Queries actually generated by SSRS other than running profile traces to capture them?
Is there some way from within the BIDS editor to see this?
You could run something like the below against your SSRS report server. You will be able to see the sql that is being execute by the report datasets.
;WITH XMLNAMESPACES (
DEFAULT 'http://schemas.microsoft.com/sqlserver/reporting/2005/01/reportdefinition',
'http://schemas.microsoft.com/SQLServer/reporting/reportdesigner' AS rd
),
ReportData AS
(
SELECT name ReportName
, x.value('CommandType[1]', 'VARCHAR(50)') AS CommandType
, x.value('CommandText[1]','VARCHAR(8000)') AS CommandText
, x.value('DataSourceName[1]','VARCHAR(50)') AS DataSource
FROM (SELECT name
, CAST(CAST(content AS VARBINARY(MAX)) AS XML) AS reportXML
FROM ReportServer.dbo.Catalog
WHERE content IS NOT NULL
AND type != 3) a
CROSS APPLY reportXML.nodes('/Report/DataSets/DataSet/Query') r(x)
)
SELECT *
FROM ReportData
In short, no. There is no good workaround. However, for development I generally created a test query alongside my work in SSRS. I would edit this inside Management Studio and then just paste the values back into BIDS. Assuming two parameters named "StudentID" and "TeacherID", the query looked like:
DECLARE #StudentID int
DECLARE #TeacherID int
SELECT #StudentID = StudentID FROM Students WHERE StudentName LIKE 'John Doe'
SELECT #TeacherID = TeacherID FROM Teachers WHERE TeacherName LIKE 'Mr. Jones'
-- PASTE IN QUERY FROM BIDS BELOW
This allowed me to use real text values from the drop-down parameter lists and simply paste in my query. Then I could optimize the query in Management Studio and then paste it back into BIDS when I was happy with the result.
What I normally do is run SQL Profiler when I run the report and pull the query out of it with the parameters.
Close the file, change the extension from .rdlc to .rdl and reopen it. It should display as HTML. Now do a search for "select" and there you go!
Related
How can I make the table looks like below turn into concatenated form
1844|a
1847|a,b
1848|34,qaz
Good day,
This question was asked with the tag "sql-server-2012", but I can't feel good to give the answer without first show how simple it is to solve these type of questions with new function STRING_AGG that was added to SQL Server 2017.
Therefore, First I will add the code for the sample DDL+DML (create the relevant table and insert sample data), which is something that the person who ask the question must ad to the question, but was not added here
Secondly I will show the solution in SQL Server 2017 and above
And finally I will give the solution for older versions like SQL Server 2012
Have fun, and I recommend to read all
DDL + DML
NOTE! Instead of posting images and stories on your table, it is always better to present us a simple way to reproduce the issue! This means that when you have question related to queries, then you should provide us with queries to create a sample table (including the indexes) and to insert sample data. In addition you should add the requested result, which was provided here.
/*************************** DDL+DML */
drop table if exists T; -- this work only from SQL Server 2016
create table T(id int, txt nvarchar(10))
GO
INSERT T(id,txt)
values (1844,'a'),(1847,'a'),(1847,'b'),(1848,'34'),(1848,'q')
GO
Select * from T
GO
Solution for SQL Server 2017 and above
/*************************** Solution */
-- New from 2016: STRING_SPLIT ( string , separator )
-- New from 2017: STRING_AGG ( expression, separator ) [ <order_clause> ]
SELECT id,STRING_AGG(ISNULL(txt,''), ',') WITHIN GROUP (order by id)
from T
group by id
GO
Solution for old versions of SQL Server
This solution was taken from this blog:
http://ariely.info/Blog/tabid/83/EntryId/152/Unsplit-Using-For-XML-with-group-by-columns.aspx
SELECT
id,
STUFF(
(
SELECT ',' + t_in.txt
FROM T t_in
WHERE (t_in.id = t_out.id)
FOR XML PATH ('')
),1,1,''
) AS NameValues
FROM T t_out
GROUP BY id
GO
I hope that this solve the question ;-)
Oracle supports dynamic XMLElement name with evalname function. Is there a similar feature in postgres to get the XMLElement name dynamically instead of using constant?
Example in ORACLE:
select xmlelement(evalname(ENAME),EMPNO) from EMP;
This statement will result in list of enames as separate xml elements.
<SMITH>7369</SMITH>
<ALLEN>7499</ALLEN>
<WARD>7521</WARD>
Not sure if postgres has something similar.
Thanks.
I was able to get a workaround to construct xml with dynamic element names in Postgres using execute format. Posting this just in case if anyone had same issue.
execute format('SELECT XMLElement(NAME %I, $1)', emp_name) USING empno from emp;
<SMITH>7369</SMITH>
<ALLEN>7499</ALLEN>
Same worked with XMLForest and having XMLAttributes inside XMLElement.
There is no such function as far as I know.
The closest you can get is adding an attribute with the empname:
select xmlelement(name emp, xmlattributes(empname), empno)
from emp;
Generates:
<emp empname="Smith">7369</emp>
<emp empname="Allend">7499</emp>
<emp empname="Ward">7521</emp>
Personally I would find that format much easier to parse e.g. in XSLT or an XML parser. Because in order to process a tag you would need to know the tag name, which you don't if the tag changes for each row - but this might just be me.
I have a table like this:
create table emp(empid, empname, sal)
insert emp values(101, 'srewt', 1500)
The table contains 10000 rows.
I also have a stored procedure like this:
create procedure p1 (#eid int)
as
begin
select * from emp where empid = #eid)
end
In SSRS I execute this procedure
exec p1 (' ')
but I have to provide user interaction to the report to pass empid value (nothing but parameter)
How can I pass a parameter to the report?
You can define the parameter in the report designer. Open the report data tab (should be in the same place, as the solution explorer. if it is not there, you can show the report data dock by opening a report, clicking on View-ReportData).
When you double click on the report dataset, you can configure the report parameters. If you chose a stored procedure with parameters as datasource, the designer should detect the parameters of the procedure automatically and fill in the values in the parameter tab for you. But make sure to check the data type, as the detected data types often are not the ones you really need.
In your dataset just pass exec p1 (#EmpID) as a query, then automatically a parameter with name EmpID will be created in Report. Here when user run the report it asks for EmpID to enter, just give the ID and run the report...
Is it possible to declare a variable within a View? For example:
Declare #SomeVar varchar(8) = 'something'
gives me the syntax error:
Incorrect syntax near the keyword 'Declare'.
You are correct. Local variables are not allowed in a VIEW.
You can set a local variable in a table valued function, which returns a result set (like a view does.)
http://msdn.microsoft.com/en-us/library/ms191165.aspx
e.g.
CREATE FUNCTION dbo.udf_foo()
RETURNS #ret TABLE (col INT)
AS
BEGIN
DECLARE #myvar INT;
SELECT #myvar = 1;
INSERT INTO #ret SELECT #myvar;
RETURN;
END;
GO
SELECT * FROM dbo.udf_foo();
GO
You could use WITH to define your expressions. Then do a simple Sub-SELECT to access those definitions.
CREATE VIEW MyView
AS
WITH MyVars (SomeVar, Var2)
AS (
SELECT
'something' AS 'SomeVar',
123 AS 'Var2'
)
SELECT *
FROM MyTable
WHERE x = (SELECT SomeVar FROM MyVars)
EDIT: I tried using a CTE on my previous answer which was incorrect, as pointed out by #bummi. This option should work instead:
Here's one option using a CROSS APPLY, to kind of work around this problem:
SELECT st.Value, Constants.CONSTANT_ONE, Constants.CONSTANT_TWO
FROM SomeTable st
CROSS APPLY (
SELECT 'Value1' AS CONSTANT_ONE,
'Value2' AS CONSTANT_TWO
) Constants
#datenstation had the correct concept. Here is a working example that uses CTE to cache variable's names:
CREATE VIEW vwImportant_Users AS
WITH params AS (
SELECT
varType='%Admin%',
varMinStatus=1)
SELECT status, name
FROM sys.sysusers, params
WHERE status > varMinStatus OR name LIKE varType
SELECT * FROM vwImportant_Users
also via JOIN
WITH params AS ( SELECT varType='%Admin%', varMinStatus=1)
SELECT status, name
FROM sys.sysusers INNER JOIN params ON 1=1
WHERE status > varMinStatus OR name LIKE varType
also via CROSS APPLY
WITH params AS ( SELECT varType='%Admin%', varMinStatus=1)
SELECT status, name
FROM sys.sysusers CROSS APPLY params
WHERE status > varMinStatus OR name LIKE varType
Yes this is correct, you can't have variables in views
(there are other restrictions too).
Views can be used for cases where the result can be replaced with a select statement.
Using functions as spencer7593 mentioned is a correct approach for dynamic data. For static data, a more performant approach which is consistent with SQL data design (versus the anti-pattern of writting massive procedural code in sprocs) is to create a separate table with the static values and join to it. This is extremely beneficial from a performace perspective since the SQL Engine can build effective execution plans around a JOIN, and you have the potential to add indexes as well if needed.
The disadvantage of using functions (or any inline calculated values) is the callout happens for every potential row returned, which is costly. Why? Because SQL has to first create a full dataset with the calculated values and then apply the WHERE clause to that dataset.
Nine times out of ten you should not need dynamically calculated cell values in your queries. Its much better to figure out what you will need, then design a data model that supports it, and populate that data model with semi-dynamic data (via batch jobs for instance) and use the SQL Engine to do the heavy lifting via standard SQL.
What I do is create a view that performs the same select as the table variable and link that view into the second view. So a view can select from another view. This achieves the same result
How often do you need to refresh the view? I have a similar case where the new data comes once a month; then I have to load it, and during the loading processes I have to create new tables. At that moment I alter my view to consider the changes.
I used as base the information in this other question:
Create View Dynamically & synonyms
In there, it is proposed to do it 2 ways:
using synonyms.
Using dynamic SQL to create view (this is what helped me achieve my result).
I have a complex query that requires a rank in it. I've learned that the standard way of doing that is by using the technique found on this page: http://thinkdiff.net/mysql/how-to-get-rank-using-mysql-query/. I'm using Infobright as the back end and it doesn't work quite as expected. That is, while a standard MySQL engine would show the rank as 1, 2, 3, 4, etc... Brighthouse (Infobright's engine) would return 1, 1, 1, 1, etc.... So I came up with a strategy of setting a variable, a function, and then execute it in the query. Here's a proof of concept query that does just that:
SET #rank = 0;
DROP FUNCTION IF EXISTS __GetRank;
DELIMITER $$
CREATE FUNCTION __GetRank() RETURNS INT
BEGIN
SET #rank = #rank + 1;
return #rank;
END$$
DELIMITER ;
select __GetRank() AS rank, id from accounts;
I then copied and pasted the function into Jasper Report's iReport and then compiled my report. After executing it, I get syntax errors. So I thought that perhaps the ; was throwing it off. So at the top of the query, I put in DELIMITER ;. This did not work either.
Is what I'm wanting to do even possible? If so, how? And if there's an Infobright way of getting a rank without writing a function, I'd be open to that too.
Infobright does not support functions.
From the site: http://www.infobright.org/forums/viewthread/1871/#7485
Indeed, IB supports stored procedures, but does not support stored functions nor user defined functions.
select if(#rank is null,#rank:= 0,#rank:= #rank +1) as rank, id from accounts
Does not work, because you cannot write to #vars in queries.
This:
SELECT
(SELECT COUNT(*)
FROM mytable t1
WHERE t1.rankedcolumn > t2.rankedcolumn) AS rank,
t2.rankedcolumn
FROM mytable t2 WHERE ...;
will work, but is very slow of course.
Disclaimer, not my code, but Jakub Wroblewski's (Infobright founder)
Hope this helps...
Here's how I solved this. I had my server side program execute a mysql script. I then took the output and converted it to a CSV. I then used this as the input data for my report. A little convoluted, but it works.