I seem to be having problems building a dataset in SSRS when the query references a SQL user defined function. e.g.
SELECT ISNULL(Period, dbo.FnuPeriodFromDate(PerBegDt)) as Period
FROM MyTab
Is it legal to do this? It rejects it as invalid syntax yet the query works in SSMS.
There are many things that the query builder will reject, that actually work fine once you render the report. For example, one of my queries uses this:
WITH X AS
(
SELECT TOP (30) n = ROW_NUMBER() OVER (ORDER BY m1.number)-1
FROM [master].dbo.spt_values AS m1
CROSS JOIN [master].dbo.spt_values AS m2
)
It throws errors at me, but the report runs fine(SSRS doesn't like the OVER keyword). If you hit 'OK' on the dataset and your 'Report Data' tab displays field names, it's still working. Just use SSMS or run the query in Visual Studio with the BI tools and ensure that your data is how you want it to be.
You can view your report data by going to the menu bar -> 'View' -> 'Report Data'
Sonny's suggestion was the correct solution - i.e.
"Try giving yourself rights to execute the procedure by adding this to your query: GRANT EXECUTE ON [storedProcName] TO [userName]"
many thanks.
Related
I am trying to create a SQL View in SSMS. I am using Views because they are easier to invoke from Power BI than Stored Procedures (especially when no parameters are needed).
I start by writing and testing a SQL SELECT query with an ORDER BY clause.
When I copy and paste my query in the New View:
SSMS adds a TOP (100) PERCENT to my SELECT statement.
Tells me that my ORDER BY clause (which works perfectly well in the SQL SELECT) may not work.
If you click the Help button on the dialog, you are taken to a Microsoft "Oops! No F1 help match was found" page.
My questions are:
Is TOP (100) PERCENT not implied when it is left out of a SQL Select?
Why would a View based on a SQL Select statement not like ORDER BY clauses?
SQL views to not support ORDER BY. For more detail on this, see these other posts:
Create a view with ORDER BY clause
Possible to have an OrderBy in a view?
Order BY is not supported in view in sql server
Why use Select Top 100 Percent?
As #Martin Smith said, your options are one of the following:
Put the ORDER BY in a query that references the view.
SELECT * FROM ViewName ORDER BY [...]
Do the ordering in the Power Query Editor. If you don't have any steps before this sort that break query folding, this should be translated into a native SQL query that gets evaluated on the SQL Server.
I recommend the latter since further steps can also potentially be folded in as well. Specifying your own query does not support query folding.
I have looked at the articles on stackoverflow about this issue.
I have also reviewed the article for calling stored procedures with parameters at https://www.c-sharpcorner.com/article/execute-sql-server-stored-procedure-with-user-parameter-in-power-bi/.
In my case, I have a stored procedure with no parameters.
I am unclear on how I would apply a fix-up to the M script in Power Query Editor to call a stored procedure with no parameters so that the stored procedure can be recognized and used by Power BI.
Could someone provide guidance for my scenario and steps below?
Scenario
I am using a Power BI with DirectQuery.
I need an ordered list or rows from my database. So I created a stored procedure in my SQL database that simply wraps a SQL SELECT statement with an ORDER BY clause.
The stored procedure has no parameters.
Steps
In SQL Server Management Studio, I create and test my stored procedure.
CREATE PROCEDURE [dbo].[pbiGetFileInfo]
AS
BEGIN
SET NOCOUNT ON;
SELECT dbo.CurrentReport.JobId AS CurrentJobId,
dbo.jobs.id AS JobId,
dbo.JobInstruments.Id AS JobInstrumentId,
dbo.JobInstruments.InstrumentDescription,
dbo.JobInstruments.Notes,
dbo.JobInstruments.Latitude,
dbo.JobInstruments.Longitude,
dbo.JobInstruments.Depth,
dbo.jobinstrumentimport.filename,
dbo.jobinstrumentimport.mindate AS FromDate,
dbo.jobinstrumentimport.maxdate AS ToDate,
DATEDIFF(hour, dbo.jobinstrumentimport.mindate, dbo.jobinstrumentimport.maxdate) AS duration_hours
FROM dbo.CurrentReport INNER JOIN
dbo.jobs ON dbo.CurrentReport.JobId = dbo.jobs.id INNER JOIN
dbo.JobInstruments ON dbo.jobs.id = dbo.JobInstruments.JobId INNER JOIN
dbo.jobinstrumentimport ON dbo.JobInstruments.Id = dbo.jobinstrumentimport.jobinstrumentid
ORDER BY JobInstruments.Id, FromDate
END
GO
In Power BI, I click the Transform Data button to launch the Power Query Editor.
Under queries, I right-click the first empty entry in the Queries pane and highlight the New Query item and click SQL Server from the context menu.
In the SQL Server Database dialog, I enter the Server and Database.
In the SQL Server Database dialog, I click the Advanced Options link to expand the dialog and show the SQL statement (optional, requires database) field.
In the SQL statement (optional, requires database), I enter EXEC [dbo].[pbiGetFileInfo] and click the OK button.
A truncated preview of the data returned by the stored procedure is displayed.
I click OK at the bottom of the preview.
A new entry Query1 appears in the Queries pane.
I right-click the new Query1 entry and rename it to pbiGetFileInfo. The M syntax that appears for the query at this point is:
= Sql.Database("Server Name", "NWBDatabase", [Query="EXEC [dbo].[pbiGetFileInfo]"])
At this point, if I click "Apply" from the Power Query Editor Ribbon, I will get the error message:
Incorrect syntax near the keyword 'EXEC'. Incorrect syntax near ')'
I click the Advanced Editor button on the toolbar. The M script for the pbiGetFileInfo query is:
let
Source = Sql.Database("Server Name", "NWBDatabase", [Query="EXEC [dbo].[pbiGetFileInfo]"])
in
Source
At this point, I am stuck.
My questions are:
The stored procedure has no parameters. Do I need to add a SQLSource prefix to the M script? If I do need a SQLSource, what would that look like?
let
SQLSource ...
let
Source = Sql.Database("Server Name", "NWBDatabase", [Query="EXEC [dbo].[pbiGetFileInfo]"])
in
Source
in
SQLSource
One thought is to create a view in SQL that calls the stored procedure. I have tried this and found that the view returns the same warning in Power BI as you would see if you tried to create a View with an ORDER BY in SQL. Calling views from Power BI is problematic at best.
Is there any way to write a stored procedure in SQL that minimizes the workarounds required to use them from Power BI?
Updates
I cannot call a stored procedure from Power BI under DirectQuery. It returns the same error `Incorrect syntax near 'EXEC' message. I need to see the DAX that is created to find the source of this error.
If I try the raw SQL Select from the stored procedure that I am trying to call, I get the following error:
Microsoft SQL: The ORDER BY clause is invalid in views.
Note: this is using straight SQL SELECT. The word VIEW is does not exist in the SQL SYNTAX at all.
A SQL Select that calls a VIEW only works if the calling outer SELECT contains a TOP (100) PERCENT clause. For example:
My view named [pbiGetFileInfo] contains the following SELECT statement:
SELECT dbo.CurrentReport.JobId AS CurrentJobId,
dbo.jobs.id AS JobId,
dbo.JobInstruments.Id AS JobInstrumentId,
dbo.JobInstruments.InstrumentDescription,
dbo.JobInstruments.Notes,
dbo.JobInstruments.Latitude,
dbo.JobInstruments.Longitude,
dbo.jobinstrumentimport.filename,
dbo.jobinstrumentimport.mindate AS FromDate,
dbo.jobinstrumentimport.maxdate AS ToDate,
DATEDIFF(hour, dbo.jobinstrumentimport.mindate, dbo.jobinstrumentimport.maxdate) AS duration_hours
FROM dbo.CurrentReport INNER JOIN
dbo.jobs ON dbo.CurrentReport.JobId = dbo.jobs.id INNER JOIN
dbo.JobInstruments ON dbo.jobs.id = dbo.JobInstruments.JobId INNER JOIN
dbo.jobinstrumentimport ON dbo.JobInstruments.Id = dbo.jobinstrumentimport.jobinstrumentid
The view itself does not contain an ORDER BY clause.
When I try to call this from a SQL SELECT statement:
SELECT * FROM [dbo].[pbiGetFileInfo] ORDER BY Id,FromDate
I get the error:
Microsoft SQL: The ORDER BY clause is invalid in views...
It works if I revise the SELECT to:
SELECT TOP (100) PERCENT * FROM [dbo].[pbiGetFileInfo] ORDER BY Id,FromDate
But, I am not sure it this will work correctly in Power BI DirectQuery.
My first thought is that Power BI seems to treat everything as a SQL VIEW. So all data sources are subject to the limitations of views. None of the advantages of sorting on a SQL Server are actually available in Power BI under DirectQuery. If you have to set the sort order in Power BI, there may be significant performance penalties.
I am experimenting with Table-Valued Functions (but have no faith that this will work in Power BI).
I have created a report (call it Primary) and a drillthrough (call it Secondary) in Report Builder. Each of these has a SQL statement.
When executed in SQL Server Management Studio, SQL statements work as expected.
However, when the Primary.rdl and Secondary.rdl are uploaded to Report Manager (the web interface in Internet Explorer), they do not generate the correct data when run.
Because of this, I think the problem is not the SQL statements. I think it's something to do with the Report Manager.
Primary SQL statement:
This statement grabs a bunch of user data from multiple tables and checks if their passwords are acceptable. It populates a list of users whose passwords failed the check.
This is pseudocode so pardon inconsistencies in var names
with details as (
select u.userid
, u.password
, u.firstname
, u.lastname
, u.userdescription
, u.status
, u.lastlog
, dbo.IsPassswordAcceptable(u.userid, u.password) as passStatus
from masterListOfUsers as u
)
select d.*, p.datavalue
from details as d
left join passwordDetailList as p
on p.keyvalue = d.passStatus
and p.datatype = 'ERRORMESSAGE'
where d.passStatus <> 1
and d.passStatus <> -5
and d.status = (#USERSTATUS) -- only user ids in use
;
Secondary SQL statement:
This statement is a drillthrough. The person running the report can click on a userID in the above list. A drillthrough is performed where the contact information for that userID is populated.
This is pseudocode so pardon inconsistencies in var names
SELECT
m.userid
, c.address
, c.city
, c.state
, c.zip
, c.cphone
FROM userMasterList AS m
left join userDetailList AS d
ON d.userid = m.userid
left join anotherList as e on d.fullkey = e.fullkey
left join yetAnotherList AS c
WHERE m.userid = #USERID;
Expected result:
When the user runs the Primary, a list of users with bad passwords is populated. Each user's userID can be clicked on, which triggers the Secondary to populate the location/contact info associated with that userID.
Actual result:
On userID click, the Secondary fails to populate any location/contact info associated with the userID. This occurs only sometimes. Other times, it works fine.
I made a list of these "empty" userIDs and ran the Secondary's SQL statement in Management Studio, and it populates all the expected location/contact info.
Solutions I've tried:
I'm absolutely stumped. I've triple-checked the SQL statements and tested them in Management Studio. I've re-uploaded both .rdl files to Report Manager. I've reassigned the Secondary to the Primary via the "Create Linked Report" option in Report Manager AND ALSO in Report Builder's Action > Go To Report option.
What else can I do?
This is not really an answer as such, but a list of things I would work thru in the same situation.
Run SQL Profiler to trace your report session and make sure the query being executed is what you expect. Depending on how parameters are passed to the SQL statements, SSRS will not always do things quite the way you expected.
Check if you can repeat the issue by just running the drill thru report on it's own (not via the primary report)
Determine if the issue is consistent with specific userids? i.e. does user A always fail and User B always work? If the issue is consistent, the issue is most likely to be data related. Check for special characters in the fields that appear to be blank such as chr(13)/chr(10), they may just be forcing the 'real' content onto a new line inside the textbox.
Add some debug info to your report to help identify the issue such as:
a. Edit the dataset query to add some more info from dataset itself SELECT .... , c.addrees, len(c.address) as AddresLen from .... You can add this to a copy of your report
b. Add another textbox that does the same thing but directly in SSRS (e.g. expression would be something like =LEN(Fields!address.Value)). You then have two numbers to compare against what you can see. If the LEN textbox says 20 but the address field appears blank, then special characters could be the issue.
After hours of tinkering, the problem ended up being that the userID was being trimmed of all leading and trailing whitespace by some of the query tools but not by the SQL statements themselves. So when the final report is run in Report Manager, the data is queried with superfluous whitespace, resulting in no data being found.
This issue is resolved when the data points are trimmed.
The fixed Secondary SQL statement:
This is pseudocode so pardon inconsistencies in var names
SELECT
rtrim(m.userid) as userid
, rtrim(c.address) as address
, rtrim(c.city) as city
, rtrim(c.state) as state
, rtrim(c.zip) as zip
, rtrim(c.phone) as phone
FROM userMasterList AS m
left join userDetailList AS d
ON d.userid = m.userid
left join anotherList as e on d.fullkey = e.fullkey
left join yetAnotherList AS c
WHERE ltrim(rtrim(m.userid)) = ltrim(rtrim(#USERID));
Is it possible to get exactly the same parameters as shown in the All execution Overview report (see the printscreen below)?
I was trying to use the table [internal].[execution_parameter_values] from SSISDB and filter it via execution_id, nevertheless it returns much more parameters than in the report. I have also tried to filter it with table attribute "value_set", "object_type", etc. but still it did not return the same list as in the report.
Reference:
https://learn.microsoft.com/en-us/sql/integration-services/system-views/views-integration-services-catalog?view=sql-server-2017
execution_parameter_value:
Displays the actual parameter values that
are used by Integration Services packages during an instance of
execution.
Whenever the package is executed, records are inserted into that table. You need to determine the execution_id that you want to filter on.
You can get that from [catalog].[executions] in the SSIS DB. Filter based on your project or package and when it was executed.
Or you will also see that in the execution overview report as "Operation ID":
You can then filter based on that value:
SELECT * FROM [internal].[execution_parameter_values]
WHERE [execution_id] = 16529
Overview report in the SSIS catalog shows only TOP 25 used parameters sorted by parameter_name ASC.
Also, it is needed to filter out the records with parameter_name without "." character.
So the result T-SQL script would be:
SELECT TOP 25
[parameter_name]
,[parameter_value]
,[parameter_data_type]
FROM [SSISDB].[internal].[execution_parameter_values]
WHERE execution_id = #execution_id AND parameter_name not like '%.%'
ORDER BY parameter_name
I'm trying to create a SQL View that pulls 2 tables together each from a different DB. The SQL works fine in the query editor but when I try to run it as a view all the columns from the MSP_EpmProject table say "Unsupported DataType".
SELECT TOP (200) dbo.Project.ProjectID, dbo.Project.ProjectGUID, dbo.Project.ProjectName, dbo.Project.DefaultBaselineID,
FMM_ProjectServer_Reporting.dbo.MSP_EpmProject.ProjectName AS Expr1
FROM dbo.Project INNER JOIN
FMM_ProjectServer_Reporting.dbo.MSP_EpmProject ON dbo.Project.ProjectGUID = FMM_ProjectServer_Reporting.dbo.MSP_EpmProject.ProjectUID
Check out this bug report - http://connect.microsoft.com/SQLServer/feedback/details/464339/unsupported-data-type-reported-for-supported-data-types-in-nested-query
It appears to be a long standing issue from SQL 2005 which they still havent fixed.
The work around appears to be to not work with your view in design mode, you will have to develop this view manually in query analyzer.