I have a SSRS report which accepts a parameter (Country_Name).
This is a weekly report and needs to be generated automatically by triggering the SQL agent job. So, I have created a data driven subscription for this report and created a SSIS package to generate the report from SQL agent job.
Now the problem is : Since it is a automated report, there is no interface to pass the parameter to report. So, I have created a table to hold the list of parameters to be passed and the path to place the generated report.
Table will have 2 columns (Country_Name & Report_Path) and hold values like (India \AB123C\India) (China,\ABC\China) etc.
Depending on the parameter passed, location of the report will change. So, I used looping in data driven subscription query to get the parameter and path. Though there are multiple parameters and path for that respective parameter are returned by the query, it is picking only the first result set and generates report only for the first parameter and its specified location.
I unable to find out the solution for this. Please find the below query I have used for your reference. It would be great if I can get a solution for this.
DECLARE #MinCount INT = 1
DECLARE #Country VARCHAR(100)
DECLARE #Path VARCHAR(MAX)
DECLARE #RecordCount INT
DECLARE #CurrentDate VARCHAR(10)
DECLARE #CountryList Table (ID INT Identity(1,1),Country_Name Varchar(100),Report_path Varchar(max))
SET #RecordCount = (SELECT COUNT(*) FROM Country_List)
WHILE (#MinCOunt < = #RecordCount)
BEGIN
SET #Country = (Select Country_name from Country_List WHere ID = #MinCOunt)
SET #Path = (Select Report_Path from Country_List WHere ID = #MinCOunt)
SET #CurrentDate = ( SELECT CONVERT(char(10), GetDate(),126) as currentSysDate)
Delete from #CountryList
insert into #CountryList (Country_Name,Report_path) Values (#Country,#Path)
select 'Country_Details ' +
#CurrentDate as filename
,'Excel' as RenderFormat
, (select Name from Master where
Reference_Name = 'USER_NAME'
) as sqlUserId
,( select Value from Master where
Reference_Name = 'PASSWORD'
) as sqlPwd , (Select Country_Name from #CountryList) AS Issue_Country,
(Select Report_path from #CountryList) AS filePath_cfonereports
SET #MinCOunt = #MinCOunt + 1
END
I have resolved this issue now by using a different approach rather than using looping in subscription code. I created a reference table to store to the list of parameters as well as the corresponding path. Since this report is called from a SSIS package, I have used a variable to get the list of parameters from the reference table and a foreach loop container with Execute SQL task to pass one parameter from variable at a time and invoke the subscription. So that the report will be generated for that parameter passed and in the path specified. This foreach loop container will loop n times based on the count of parameters in the variable
Related
I'm creating a report in SSRS using a stored procedure. My report is simple, basically pulls basic information of a client in different programs.
In my stored-procedure I have two parameters: #StartDate DATETIME and #VendorId INT = NULL.
I'm setting #Vendorid to NULL because I would like to get all clients in every program.
I have two options in my sproc:
IF (#VendorID > 0) --Select Program
BEGIN
INSERT INTO #Report
SELECT * FROM table1 WHERE VendorId = #VendorId
END
IF (#VendorID IS NULL) --All Programs
BEGIN
INSERT INTO #Report
SELECT * FROM table1
END
This report gives me the flexibility to get clients from different programs from the day they were enrolled. Hence, if I want to get all clients in every program I simply execute the sproc with the #StartDate parameter. I would like to do the same in SSRS. I just can't figure how to set the #vendorid parameter function the same way in my sproc.
Any insight would be helpful!
AS you know generally in SSRS you can have parameters as Query string or selected value
so
Just add
SELECT * FROM table1 WHERE #VendorId=-1 OR VendorId = #VendorId
To specify a custom default value here -1
Switch to Design view.
In the Report Data pane, right-click #VendorId, and then click Parameter Properties.
Click Default Values > Specify values > Add. A new value row is added.
In Value, type -1.
Click OK.
Preview the report.
You have drop down and you can use -1 as none selected.
https://learn.microsoft.com/en-us/sql/reporting-services/tutorial-add-a-parameter-to-your-report-report-builder?view=sql-server-ver15
As part of a SSIS package I have a SQL table containing the staging table name and corresponding 'real' table name. The staging table names will change based on the date but there is a previous step that works out what the Real_Table is.
How do I loop through each one in SQL and insert all the data from the staging tables (columns are identical in both) into the real table and update the flag from 0 to 1 to mark it was done. This is my table:
Staging_Table Real_Table UpdateFlag
Customers_01012018 Customers 0
Order_01012018 Order 0
Suppliers_02022018 Suppliers 0
You can use while loop to load the data into Real tables,
DECLARE #total INT
DECLARE #start INT
DECLARE #query NVARCHAR(MAX)
DECLARE #staging_table NVARCHAR(MAX)
DECLARE #real_table NVARCHAR(MAX)
SET #start = 1
SET #total = (SELECT COUNT(*) FROM Stg_tables)
WHILE(#start <= #total)
BEGIN
SELECT TOP 1 #staging_table = Staging_Table, #real_table = Real_Table FROM Stg_tables WHERE UpdateFlag = 0
SET #query = 'INSERT INTO ' + #real_table + ' SELECT * FROM ' + #staging_table
EXEC(#query)
UPDATE Stg_tables SET UpdateFlag = 1 WHERE Staging_Table = #staging_table AND Real_Table = #real_table
SET #start = #start + 1
END
An overview of how to go about this is below. Of course make sure to match the correct configurations to your environment and set the metadata appropriately where applicable.
Create an Execute SQL Task that selects the staging and real table
names. Choose the "Full result set" ResultSet. On the Result Set
page, add an object variable and set the Result Name to 0 to use the
immediate results.
Add a Foreach Loop that is of the Foreach ADO Enumerator type. Use the object variable from the Execute SQL Task as the ADO Object Source Variable. On the Variable Mappings page, add a string variable at index 1 and 0. One of these will hold the staging table name and the other will hold the real table name. These will align with the order they were selected in the Execute SQL Task, so if you selected the staging table first there use a the variable that will hold this name at index 0.
Create another string variable that contains an expression selecting the necessary columns that will be loaded from the staging table with the variable holding this table name concatenated within in. An Example of this follows with the #[User::StagingTableVariable] variable representing the variable holding the staging table name.
Within the Foreach Loop, add Data Flow Task then add an OLE DB Source inside this. This will use the variable with the SQL selecting from the staging table, but to correctly set the metadata choose the SQL Command option and use a SQL statement that selects the same columns from an existing staging table name. Once this is set, change the ValidateExternalMetadata property to false, choose "SQL command from variable" for the Data Access Mode, and pick the variable holding the SQL statement that uses the staging table name.
Add an OLE DB Destination and connect the source to this. Like before, use an existing real table and map the columns. After this, again set ValidateExternalMetadata to false, change Data Access Mode to the use a table or view name from variable (I would recommend the fast load option), and add the variable holding the real table name.
After the Data Flow Task add another Execute SQL Task that's linked to the DFT. Create a string variable with an update statement for the mapping table where the table names originate from. Set the SQLSourceType value to variable and select this variable for the SourceVariable property. If you're using a text column in the WHERE clause of the update statement, make sure that the expression contains single quotes (') as a typical SQL update statement would.
Example OLE DB Source Variable Expression:
"SELECT ColA, ColB, ColC from YourSchema." + #[User::StagingTableVariable]
Example Variable Expression Update Command:
"UPDATE YourSchema.MappingTable SET UpdateFlag = 1 where Real_Table = '" + #[User::RealTableVariable] + "'"
I'm trying to produce a report that has a count of computer objects within many, many AD OUs from SQL Server so I can join it to other data in a SQL DB and then create a report with SSRS.
I've figured out how to do it with a single OU (which represents a physical site location with a unique code in my situation) but I need to be able to do it for all the OUs in the directory.
This is my query to get the result for 1 single OU. Any ideas?
DECLARE #SiteCode int
SET #SiteCode = 1234
DECLARE #Region nvarchar(100)
SET #Region = (
SELECT TOP 1 RegionName
FROM tbl_ADSiteInfo
WHERE SiteCode = #SiteCode
)
DECLARE #SiteName nvarchar(250)
SET #SiteName = (
SELECT TOP 1 SiteName
FROM tbl_ADSiteInfo
WHERE SiteCode = #SiteCode
)
DECLARE #SQL nvarchar(1000)
SET #SQL = '
SELECT TOP 901 COUNT(*) As ''Count''
FROM OpenQuery(
ADSI,
''
SELECT distinguishedName,extensionAttribute3,extensionAttribute4,extensionAttribute2, name
FROM ''''LDAP://OU=Computers,OU=' + #SiteName + ',OU=' + #Region + ',OU=Branches,DC=COMPANY,DC=COM''''
WHERE objectClass = ''''Computer''''
''
) AS tblADSI
'
exec dbo.sp_executeSQL #SQL
I figured out how to do this myself after thinking about it for a while.
First, I query an existing table to get a dataset of unique IDs in my org for our sites (SiteCode) and write them to a temp table with another column called 'Processed' that has the value of 0.
Then, I do a WHILE loop that has the condition of SELECT COUNT(SiteCode) FROM #TMP WHERE Processed = 0 > 1
Then I do a SELECT TOP 1 with a WHERE Processed = '0' to get a SiteCode and use that to query another table to get the LDAP path to that site's container, and then do the LDAP query for the count of Computer objects and write the value into yet another table that will hold the results I want. When I've got the data I need, I set that record to Processed = '1' and then the loop continues.
Eventually, all the sites will have Processed = '1' and the loop will finish. Then I DROP the temp table as I don't need it anymore.
I'm a bit concerned that the execution time will blow out doing it this way but apart from hand counting, I'm not sure what else to do, and I'm pretty happy with it anyway :)
I am building a query using the JPA's CriteriaBuilder to call the SQL Server exist function to find data based on an XML field and it is failing to run due to a The argument 1 of the XML data type method "exist" must be a string literal. error.
I traced the SQL generated and get the same error when I try the query in SQL Server Management Studio. I've simplified the SQL to the following for reference
declare #p1 int
set #p1=NULL
exec sp_prepexec #p1 output,
N'#P0 varchar(8000)',
N'select id, name from mytable where xmlfield.exist(#P0)=1 order by id desc',
'true()'
select #p1
The interesting thing is when I try the query by itself, it runs fine and returns the results.
select id, name from mytable where xmlfield.exist('true()')=1 order by id desc;
Any thoughts on why the generated parameterized SQL statement generated does not work?
As the error message states, the value passed into the "exist" function must be a string literal. The example given is trying to pass a variable into the function, but then when you're running the query by itself it works just fine because you're passing in a string literal.
For example...
DECLARE #xml XML = '';
DECLARE #P0 NVARCHAR(500) = 'true()';
SELECT #xml.exist(#P0) -- will not work
SELECT #xml.exist('true()') -- will work
For the longest time I thought this made these functions worthless because I didn't know you could use variables within the string literal. Here is an example:
DECLARE #xml XML = '<root><item id="1" /><item id="2"><test /></item></root>';
DECLARE #item_id INT;
SET #item_id = 1; -- "test" element does not exist
SELECT #xml.exist('/root/item[#id=sql:variable("#item_id")]/test')
SET #item_id = 2; -- "test" element does exist
SELECT #xml.exist('/root/item[#id=sql:variable("#item_id")]/test')
I have a stored procedure which returns user Token if authentication passes like this
BEGIN
SET FMTONLY OFF --Tricky Part
DECLARE #token uniqueidentifier
DECLARE #user_id as int
SET #user_id = (SELECT UserID FROM Users
WHERE #email = Email AND #password = PasswordKey)
IF #user_id IS NOT NULL
BEGIN
SET #token = NEWID()
UPDATE Users SET Token = #token
WHERE UserID = #user_id
SELECT * FROM Users WHERE UserID = #user_id
END
END
Without SET FMTONLY OFF it returns Token BUT only if user entered correct cardinalities else error
A member of the type, 'Token', does not have a corresponding column in the data reader with the same name.
occurs.
Now I have another stored procedure (almost same as this one) which returns single Product determined by ID which I pass to the stored procedure and it works fine even when I send non-existing ones. In function import, one stored procedure shows me columns which returns and another one doesn't. For clarity here are two images which shows stored procedures and function import Images
Instead of using:
SELECT * FROM Users WHERE UserID = #user_id
List out the names of the columns that you wish to return from the Users table instead of just using SELECT *.
SELECT ColumnName,
AnotherColumn,
YouGetThePoint
FROM ...
It sounds like the DataReader is being populated with column names that are different than the expected column names. Have you stepped through with a debugger and/or listed out the actual column names that are being returned from the procedures to is if they are just being given arbitrary names (e.g. T1, T2).