display passed parameter in an ssrs report even if there are no associated records in the database - sql

I need to create an SSRS report that is passed a list of parameters and return all the parameters, even if there are no records associated with the parameter. I have posted below of what I am trying to accomplish.
Passed parameters: 12388501, 1238853, 1238858, 123885900, 12388573
And would like the final report to look like the example below:
The parameters passed in this example are Account Numbers. How can I get the Account Number to display as a record even though it is not contained in the database?
I am using SQL Server 2012 database, SSMS for development of the query and will ultimately create the report in SSRS.
I hope my wording of this question makes sense. If there is anything missing in my query please let me know and I will provide it. Thanks in advance!

Step 1: Split your string into rows of a table. My understanding is that Erland Sommarskog is regarded as an authority on handling lists in SQL Server: Arrays and Lists in SQL Server 2008
Using Table-Valued Parameters (revised in 2012. He has a page devoted to the broader topic/earlier SQL Server versions at Arrays and Lists in SQL Server.) There are other methods for splitting strings into table-valued parameters via user-defined functions, etc. that may perform reasonably well for small lists similar to what you have here.
Step 2: using that table-valued parameter that you've populated from the splitting of the string parameter, form your query like the one below. The INNER JOIN in the first SELECT will give you only those records that match an AccountNumber in your inline table and the LEFT OUTER JOIN with the WHERE clause in the second SELECT will give you only AccountNumber values that don't exist in myTable. You can substitute other values for the NULL values I've stubbed in as long as they match the data types of the corresponding fields in myTable.
SELECT mt.AccountNumber,mt.LastName,mt.FirstName,mt.ContactNumber,mt.Address,mt.City,mt.State,mt.Zip
FROM myTable mt JOIN #t t ON mt.AccountNumber = t.AccountNumber
UNION
SELECT t.AccountNumber,NULL LastName,NULL FirstName,NULL ContactNumber,NULL Address,NULL City,NULL State, NULL Zip
FROM #t t
LEFT OUTER JOIN myTable mt ON t.AccountNumber = mt.AccountNumber
WHERE mt.AccountNumber IS NULL

Related

Extract db objects dependencies from SSRS dataset with inline query (Query Type : Text)

I am dealing with a specific problem of identifying the dependent db objects for any SSRS RDL.
I have a good understanding of if any dataset have stored procedure as the query in a RDL then I can reference the associated stored procedure and get all the dependent objects (details can be found here: Different Ways to Find SQL Server Object Dependencies)
But I am looking specifically for the datasets with text query or inline query for any rdl. I am able to extract the CommandText from the XML of the rdl but I am not sure how to extract db objects like sp, table, views columns form a command text which is inline query in the rdl.
For example if I extract below query from XML commandText (this is a hypothetical query, names are not standardized in the database like vw_ for views , udf_ for functions):
-----This query serves Report ABC
SELECT DATE
,[amount]
,teamID = (SELECT TeamID FROM Sales.[getSalesPerson](r.date) as s WHERE R.[SalesPersonName] = S.[SalesPersonName])
,[channel]
,[product]
,[Item]
,r.[M_ID]
,Amount
,M.[Type]
FROM dbo.FactTable AS R
LEFT JOIN sp_Channel C ON R.[Channel_ID] = C.[Channel_ID]
LEFT JOIN Marketing.vw_M M ON R.[M_ID] = M.[M_ID]
Is there a way to identify that this query have dependent object as below:
ObjectName ObjectType
------------------------------------------
dbo.FactTable Table
sp_Channel Stored Procedure
Marketing.vw_M View
Sales.[getSalesPerson] Function
It is not easy to extract object names from an SQL command since they may be written in different ways (with/without schemas, databases name included ...)
But there are many option to extract objects from an SQL query that you can try:
Using Regular expressions, As example: You have to search for the words located after the following keywords:
TRUNCATE TABLE
FROM
UPDATE
JOIN
The following code is a C# example:
Regex regex = new Regex(#"\bJOIN\s+(?<Retrieve>[a-zA-Z\._\d\[\]]+)\b|\bFROM\s+(?<Retrieve>[a-zA-Z\._\d\[\]]+)\b|\bUPDATE\s+(?<Update>[a-zA-Z\._\d]+)\b|\bINSERT\s+(?:\bINTO\b)?\s+(?<Insert>[a-zA-Z\._\d]+)\b|\bTRUNCATE\s+TABLE\s+(?<Delete>[a-zA-Z\._\d]+)\b|\bDELETE\s+(?:\bFROM\b)?\s+(?<Delete>[a-zA-Z\._\d]+)\b");
var obj = regex.Matches(sql);
foreach(Match m in obj)
{
Console.WriteLine(m.ToString().Substring(m.ToString().IndexOf(" ")).Trim());
}
Output
Then you have to clean and join the result with the sys.objects tables from the SQL Server database.
Using a SQL parser, as example:
SQL Parser
SQL Parser - Code Project
You can refer to the following very helpful links for additional information:
Regular expression to find all table names in a query
Parsing SQL code in C#
If your reports are connecting to SQLServer and you have access you could try to get the execution plan with SET SHOWPLAN_XML ON and parse it.
Relevant thread for the parsing:extracting-data-from-sql-servers-xml-execution-plan

Sql loop through the values on a table

first off, noob alert! :))
I need to construct a query that runs on many tables. The tables vary on name just on the last digits as per client code. The thing is, the values that change aren't sequential so looping as in i=1,2,3,... does not work. A possible solution would be to have those values on a given field on an other table.
Here is the code for the first two clients 015 and 061. The leading zero(s) must are essential.
SELECT LnMov2017015.CConta, RsMov2017015.DR, RsMov2017015.NInt, "015" AS CodCli
FROM LnMov2017015 INNER JOIN RsMov2017015 ON LnMov2017015.NReg = RsMov2017015.NReg
WHERE (((LnMov2017015.CConta)="6" And (LnMov2017015.CConta)="7") AND ((RsMov2017015.DR)=9999))
UNION SELECT LnMov2017061.CConta, RsMov2017061.DR, RsMov2017061.NInt, "061" AS CodCli
FROM LnMov2017061 INNER JOIN RsMov2017061 ON LnMov2017061.NReg = RsMov2017061.NReg
WHERE (((LnMov2017061.CConta)="6" And (LnMov2017061.CConta)="7") AND ((RsMov2017061.DR)=9999))
...
So for the first SELECT the table Name is LnMov2017015, the ending 015 being the value, the client code, that changes from table to table e.g. in the second SELECT the table name is LnMov2017061 (061) being what distinguishes the table.
For each client code there are two tables e.g. LnMov2017015 and RsMov2017015 (LnMov2017061 and RsMov2017061 for the second set client shown).
Is there a way that I can build the SQL, based upon the example SQL above?
Does anyone have an idea for a solution? :)
Apparently it is possible to build a query object to read data in another db without establishing table link. Just tested and to my surprise it works. Example:
SELECT * FROM [SoilsAgg] IN "C:\Users\Owner\June\DOT\Lab\Editing\ConstructionData.accdb";
I was already using this structure in VBA to execute DELETE and UPDATE action statements.
Solution found :)
Thank you all for your input.
Instead of linking 100 tables (password protected), I'll access them with SLQ
FROM Table2 IN '' ';database=C:\db\db2.mdb;PWD=mypwd'
And merge them all with a query, before any other thing!

Dynamic SQL queries as parameter

I need a Report where a user has to choose 2 parameters. The first parameter contains the years (2017, 2016...), and the second one contains the ID process. Depending on the process that the user chooses, the SQL statement will be one or another. The parameter year is part of the WHERE clause of the SQL contained in the second parameter.
So I have this report with 2 parameters (param_year, Indicador). Query parameter is done using a table datasource, where the IDs column contains the SQL sentences and the Values column contains the text the user must select.
So what I'm doing next is to set ${Indicador} as the SQL statement in the JDBC connection that I have done to the Database. This is reporting me an SQL error
"Failed at query: ${Indicador}.
Any suggestions will be appreciated. Thanks in advance.
Another option is to create multiple datasources in your Master/sub report, then select appropriate datasource using PRD expression on Master/sub Report -> Attributes -> query -> name attribute.
More detailed explanation:
Create a query (I mean a query as a PRD object, which uses the PRD datasource) for every SQL string you need and move the SQL strings from the parameter table into Report Designer queries definitions.
Replace the SQL strings in your parameter table with names of corresponding queries, e.g:
Use the value of your parameter (which should be equal to the PRD query name) as value for Master/sub Report -> Attributes -> query -> name attribute:
You need Pentaho Data Integration to do this kind of dynamic query
If the table structure (output columns) for both queries is the same, you could put them together into one big SQL statement with UNION ALL and put in each query "WHERE ${Indicador} = ValueToRunThisQuery".
The optimizer should be smart enough to know the not-selected subquery is going to return zero rows and not even run it. You can supply a few null columns if one query has fewer columns, but the data types have to be the same for filled columns.
If the output table structure is different between the two queries they should be in different data sources, or even reports.
SELECT ID, BLA, BLA, BLA, ONLY_IN_A
FROM TABLE A
WHERE ${Indicador} = "S010"
UNION ALL
SELECT ID, BLA, BLA, BLA, NULL
FROM TABLE B
WHERE ${Indicador} = "S020"

Using local variable for "IN" criteria condition with SQL Server [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
SQL : in clause in storedprocedure:how to pass values
I'm using MS SQL Server 2005, and trying to basically script a 2-step process:
Query a table for a list of IDs matching certain criteria
Update a field in that table, where the ID is in the list of IDs returned by the first
With the catch being that steps 1 and 2 might be separated by a considerable time delay and executed in different sessions. Essential the list of IDs used in #2 is historical data: the values which #1 returned at a past point in time.
What I've attempted to do is write all of IDs from #1 into a varchar(8000) in "##, ##, ##, ##," format (this part is working great), and then use that string like:
UPDATE table SET field=newValue WHERE (id IN (#varcharOfCommaSeparatedIDs))
But this is giving me a syntax error, stating that it cannot convert that varchar value into whatever is needed (the error message is being truncated)
Is there a way to do this without putting the entire SQL command into a string and executing that (using EXEC or sp_executesql)? After years of avoiding injection attacks I have a somewhat instinctive (and perhaps irrational) aversion to "dynamic SQL"
If you're passing the values around between SP's on the SQL Server, I highly recommend storing the values in tables...
- Temp Tables (#mytable)
- Table Variables (#table)
- Real Tables
In SQL Server 2008 onwards you can have table valued input parameters...
If you're passing the values in from an app, the dread comma-separated-string is indeed useful. There are many answers on SO that give Table Valued Functions for turning a string into a table of ids, read to be joined on.
SELECT
*
FROM
foo
INNER JOIN
dbo.bar(#mystring) AS bar
ON foo.id = bar.id
Just write it out to a table.
IF EXISTS (SELECT 1 FROM Database.dbo.MyHoldingTable)
DROP TABLE Database.dbo.MyHoldingTable
SELECT <fields>
INTO Database.dbo.MyHoldingTable
FROM <other table>
WHERE <conditions>
Then, later:
UPDATE OtherTable
Set Column=NewValue
WHERE ID IN (SELECT id FROM Database.dbo.MyHoldingTable)
Also note you could also use an INNER JOIN on your table instead of a IN clause if you prefer.

Jet engine (Access) : Passing a list of values to a stored procedure

I am currently writing a VBA-based Excel add-in that's heavily based on a Jet database backend (I use the Office 2003 suite -- the problem would be the same with a more recent version of Office anyway).
During the initialization of my app, I create stored procedures that are defined in a text file. Those procedures are called by my app when needed.
Let me take a simple example to describe my issue: suppose that my app allows end-users to select the identifiers of orders for which they'd like details. Here's the table definition:
Table tblOrders: OrderID LONG, OrderDate DATE, (other fields)
The end-user may select one or more OrderIDs, displayed in a form - s/he just has to tick the checkbox of the relevant OrderIDs for which s/he'd like details (OrderDate, etc).
Because I don't know in advance how many OrderID s/he will select, I could dynamically create the SQL query in the VBA code by cascading WHERE clauses based on the choices made on the form:
SELECT * FROM tblOrders WHERE OrderID = 1 OR OrderID = 2 OR OrderID = 3
or, much simpler, by using the IN keyword:
SELECT * FROM tblOrders WHERE OrderID IN (1,2,3)
Now if I turn this simple query into a stored procedure so that I can dynamically pass list of OrderIDs I want to be displayed, how should I do? I already tried things like:
CREATE PROCEDURE spTest (#OrderList varchar) AS
SELECT * FROM tblOrders WHERE OrderID IN (#OrderList)
But this does not work (I was expecting that), because #OrderList is interpreted as a string (e.g. "1,2,3") and not as a list of long values. (I adapted from code found here: Passing a list/array to SQL Server stored procedure)
I'd like to avoid dealing with this issue via pure VBA code (i.e. dynamically assigning list of values to a query that is hardcoded in my application) as much as possible. I'd understand if ever this is not possible.
Any clue?
You can create the query-statement string dynamically. In SQL Server you can have a function whose return value is a TABLE, and invoke that function inline as if it were a table. Or in JET you could also create a kludge -- a temporary table (or persistent table that serves the function of a temporary table) that contains the values in your in-list, one per row, and join on that table. The query would thus be a two-step process: 1) populate temp table with INLIST values, then 2) execute the query joining on the temp table.
MYTEMPTABLE
autoincrementing id
QueryID [some value to identify the current query, perhaps a GUID]
myvalue one of the values in your in-list, string
select * from foo
inner join MYTEMPTABLE on foo.column = MYTEMPTABLE.myvalue and MYTEMPTABLE.QueryId = ?
[cannot recall if JET allows ANDs in INNER JOIN as SQL Server does --
if not, adjust syntax accordingly]
instead of
select * from foo where foo.column IN (... )
In this way you could have the same table handle multiple queries concurrently, because each query would have a unique identifier. You could delete the in-list rows after you're finished with them:
DELETE FROM MYTEMPTABLE where QueryID = ?
P.S. There would be several ways of handling data type issues for the join. You could cast the string value in MYTEMPTABLE as required, or you could have multiple columns in MYTEMPTABLE of varying datatypes, inserting into and joining on the correct column:
MYTEMPTABLE
id
queryid
mytextvalue
myintvalue
mymoneyvalue
etc