Cognos Report re-issues multiple queries instead of doing more local processing, slow report - cognos-10

I have a Cognos report that I would like to try and speed up if possible. The report takes 4 minutes when I direct the output to HTML (including jumping to the last page to ensure that the whole report is created), 7 minutes when directing output to EXCEL and 8 minutes for a PDF.
The report uses a single Query subject which is associated with a database VIEW. When I select * from the view, the view returns 200 rows in 28 seconds. This is the only query in my report.
I have 2 Cross tabs that are both bound to this one Cognos query. The first crosstab has section breaks on a column "FUNDING REPORT NAME", the second crosstab one does not, instead it summarizes across all FUNDING REPORT NAMES.
I then group the Report Page on two columns, "REPORT GROUP" and "LEGAL ENTITY." This leads to the creation of a separate tab for each distinct pair of values. On each tab, Cognos auto filters and summarizes the data for the current value of REPORT GROUP/LEGAL ENTITY.
I believe that the report is taking longer than expected because Cognos is executing multiple queries against the view instead of only executing it once. What I would like Cognos to do for performance reasons, is to return all 200 of the rows in the View, store the results locally and then query against these rows to identify the DISTINCT values of REPORT GROUP and LEGAL ENTITY and, within this grouping, summarize the local data within the current FUNDING REPORT NAME. Instead, it issues multiple queries against the view to get this information instead of doing local processing of the small resultset.
In order to get Cognos to identify the distinct values to break on and summarize locally, I tried experimenting with the following property settings:
Set "RollUPProcessing" property on Query = Local
Set "Use Local cache" property On Query = Yes
Set the "Query Process" property on the Data Source object in the Model to "Limited Local"
However, these changes seemed to have no effect on the execution time.
Is there anything that I can do to make this report execute faster? HTML is considerable faster but Excel is the requirement. Is there anything that I can do to spedd up the production of the report when direvcted to Excel?
Here are the 4 Cognos syntax queries that Cognos says it is excuting. There is only one Query in my report that, again returns all rows 200 records, in a VIEW.
select distinct
"MLR_ROLL_FWD"."REPORT_GROUP" "Report_group"
, "MLR_ROLL_FWD"."LEGAL_ENTTY_NAME" "Legal_Entity_Name"
from
MYSCHEMA."MLR_ROLL_FWD_V" "MLR_ROLL_FWD"
order by
"Report_group" asc
, "Legal_Entity_Name" asc
FOR FETCH ONLY
select distinct
"MLR_ROLL_FWD"."FUNDNG_RPT_NM" "Funding_Report_Name"
,"MLR_ROLL_FWD"."REPORT_GROUP" "Report_group"
,"MLR_ROLL_FWD"."LEGAL_ENTTY_NAME" "Legal_Entity_Name"
from
MYSCHEMA."MLR_ROLL_FWD_V" "MLR_ROLL_FWD"
order by
"Funding_Report_Name" asc
FOR FETCH ONLY
select
"MLR_ROLL_FWD"."REPORT_GROUP" "Report_groupkey"
,"MLR_ROLL_FWD"."LEGAL_ENTTY_NAME" "Legal_Entity_Namekey"
,case
when "MLR_ROLL_FWD"."SERVICE_YEAR" <> 9999 then
'Service Year ' || "MLR_ROLL_FWD"."SERVICE_YEAR"
else 'Total'
end "levelkey"
,"MLR_ROLL_FWD"."YEAR_QUARTER" "Year_Quarterkey"
,sum("MLR_ROLL_FWD"."BEG_BAL_AMT") "Beginning_Gross_Balance"
,sum("MLR_ROLL_FWD"."REBATE_CSH_AMT") "Cash_Collection"
,sum("MLR_ROLL_FWD"."REBATE_BILLD_AMT") "Current_Billing_AMT"
,sum("MLR_ROLL_FWD"."REBATE_UNDR_OVR_PAYMT_AMT") "Over_Under_Payment_AMT"
,sum("MLR_ROLL_FWD"."REBATE_RECVBL_MANL_ADJ_AMT") "RXP_Adjustment_AMT"
,sum ("MLR_ROLL_FWD"."REBATE_RECVBL_BUMP_UP_AMT") "RXP_Bump_Up_Adjustment_AMT"
,sum("MLR_ROLL_FWD"."PYE_RECVBL_BUMP_UP_REVSL_AMT") "RXP_Bump_Up_Reversal_AMT"
,sum("MLR_ROLL_FWD"."GL_REBATE_RECVBL_AMT") "Ending_Balance__Net_"
from
MYSCHEMA."MLR_ROLL_FWD_V" "MLR_ROLL_FWD"
group by
"MLR_ROLL_FWD"."REPORT_GROUP"
,"MLR_ROLL_FWD"."LEGAL_ENTTY_NAME",
case
when "MLR_ROLL_FWD"."SERVICE_YEAR" <> 9999
then 'Service Year ' || "MLR_ROLL_FWD"."SERVICE_YEAR"
else 'Total'
end
,"MLR_ROLL_FWD"."YEAR_QUARTER"
FOR FETCH ONLY
select
"MLR_ROLL_FWD"."REPORT_GROUP" " Report_groupkey"
,"MLR_ROLL_FWD"."LEGAL_ENTTY_NAME" "Legal_Entity_Namekey"
, case when "MLR_ROLL_FWD"."SERVICE_YEAR" <> 9999
then 'Service Year ' || "MLR_ROLL_FWD"."SERVICE_YEAR"
else
'Total'
end "levelkey"
, "MLR_ROLL_FWD"."YEAR_QUARTER" "Year_Quarterkey"
, sum("MLR_ROLL_FWD"."BEG_BAL_AMT") "Beginning_Gross_Balance"
, sum("MLR_ROLL_FWD"."REBATE_CSH_AMT") "Cash_Collection"
, sum("MLR_ROLL_FWD"."REBATE_BILLD_AMT") "Current_Billing_AMT"
, sum("MLR_ROLL_FWD"."REBATE_UNDR_OVR_PAYMT_AMT") "Over_Under_Payment_AMT"
, sum("MLR_ROLL_FWD"."REBATE_RECVBL_MANL_ADJ_AMT") "RXP_Adjustment_AMT"
, sum("MLR_ROLL_FWD"."REBATE_RECVBL_BUMP_UP_AMT") "RXP_Bump_Up_Adjustment_AMT"
, sum("MLR_ROLL_FWD"."PYE_RECVBL_BUMP_UP_REVSL_AMT") "RXP_Bump_Up_Reversal_AMT"
, sum("MLR_ROLL_FWD"."GL_REBATE_RECVBL_AMT") "Ending_Balance__Net_"
from
MYSCHEMA."MLR_ROLL_FWD_V" "MLR_ROLL_FWD"
group by
"MLR_ROLL_FWD"."REPORT_GROUP"
, "MLR_ROLL_FWD"."LEGAL_ENTTY_NAME"
, case when "MLR_ROLL_FWD"."SERVICE_YEAR" <> 9999
then 'Service Year ' || "MLR_ROLL_FWD"."SERVICE_YEAR"
else 'Total' end
,"MLR_ROLL_FWD"."YEAR_QUARTER"
FOR FETCH ONLY
One huge concern is that Query 3 and 4 are identical. You would think that if I am binding 2 crosstabs to the same Query that this would not cause the SQL to be run twice.

Related

Want to use multiple conditions on same field to count the events in Data Studio

Want to use multiple conditions on event_params.value.string with different event_param.key:
I have synced my firebase data to bigQuery and trying to visualize on Data studio.Data looks like this:
Now I have event_params.value.string field which has all the values as "app" ,"4G", "App_Open","DashboardOnionActivity" and
Event Param Name field has values like : ....,Action,Label
I want to count only those App_Open which has label as DashboardOnionActivity
I was using CASE with when and Then construct as :
CASE
WHEN REGEXP_MATCH(event_params.value.string, "(?i) App_Open") THEN "1-App_Open"
WHEN REGEXP_MATCH(event_params.value.string, "(?i)selfie_capture") THEN "2-selfie_capture"
ELSE "0"
END
This gives me the count of App_Open and selfie_capture but I am not sure how to apply 2 conditions as Param Name is different for both one is Action and other is Label
One workaround can be to have separate events as DashboardOnionActivity_App_Open and Others but looking for some efficient usage if any possible
Solved it by custom query option when adding data from BigQuery(bq) connector to Data Studio:
So as data obtained in bq from firebase is nested.
Need to use unnest() in subqueries to get the values out of it.
So used query in this format in a custom query :
SELECT
event_date,event_name,event_params,
CASE
WHEN (SELECT count(*) FROM UNNEST(event_params) i where i.value.string_value='App_Open') = 1 AND (SELECT count(*) FROM UNNEST(event_params) i where i.value.string_value='DashboardOnionActivity' ) =1 THEN "1-App_Open"
ELSE "other"
END App_status
From <table_name>
​where event_params is the struct field.
Let me break down the query and explain :
SELECT count(*) FROM UNNEST(event_params) i where i.value.string_value='App_Open' :
This counts the number of 'App_Open' happen in event_params.value.string_value for one event. As there is no duplicate event_params so it is [0,1]
Similarly for DashboardOnionActivity which is 0 when it doesn't occur 1 otherwise.
Once this is added as a data source in Data Studio count can be visualized by several charts like bar, inverted bar, scorecard, etc

Returning Count of 0 for Record summaries with 0 sub-records

I am using crystal reports XI. I am working with a SQL database that was created before I got here, and I can't make changes to the tables or link structure. There are 4 tables in the database that I need for this report.
Table 1 - Companies || Fields: CompanyIDPK, CompanyName, YearActiveIDFK
Table 2 - ActiveYears || Fields: YearActiveIDPK, YearNameIDFK
Table 3 - YearNames || Fields: YearNameIDPK, YearName
Table 4 - CompanyOrders || Fields: OrderIDPK, CompanyIDFK, YearNameIDFK, OrderNumber, OrderCost
I want to create a report that is grouped by Year and by Company. I want each company to show the number of orders within each year, including showing 0 if there were no orders that year.
I can get the report to show all the companies that were in a given year, but as soon as I try to start showing a count, it only shows companies that had at least one order.
Thanks for any help!!!
My guess is that this is happening because Crystal only adds tables to your SQL query after you've added them to the designer. This happens even if you have linked your tables in the database expert.
I'm assuming you have the default join type of INNER JOIN. What's probably happening is as soon as you add your Count Summary on one of the fields in CompanyOrders, Crystal is adding it to your SQL Query.
The reason this causes a problem is because an inner join only returns records if the linked fields are in both tables. If companies haven't placed an order in the last year, they won't have any records in the CompanyOrders table. This means your SQL Query won't return any records for those companies, because those companies need to be in both tables for records to be returned.
The solution for this is to change the join type from INNER JOIN to LEFT OUTER JOIN. This can be accomplished by going into the Database Expert (Menu > Database > Database Expert), clicking the Links tab, double clicking the line that goes from your Companies to your CompanyOrders table, and selecting the Left Outer Join Radio button.
Now all of the Companies will show up, but since some don't have records in the CompanyOrders table, the count for the orders will be 0.
Let me know if this was your problem.
ZMcK
You didn't say that you couldn't create database objects, so if it is possible I would create a view or stored procedure in the SQL Server database to return the data you require in the format you want and take Crystal Reports out of the equation in terms of linking tables.

SQL Server Stored Procedure Creating Duplicates

I am running a website using SQL Server 2008 and ASP.NET 4.0. I am trying to trace an issue down that my stored procedure is creating duplicate entries for the same date. Originally I thought this may be a couple post issue but the duplicates are recording the same date down to the milliseconds. One of the duplicates is at :'2013-04-26 15:48:28.323' All of the data is exactly the same except for the id.
#check_date is an input into the stored procedure which gives us the particular date we are looking at (entries are maid daily)
#formHeaderId is grabbed earlier in the stored procedure, getting the header ID as this is a detail table with a 1 to many relationship with the header.
The #getdate() entry is where I found the duplicate entries, there are entries with the exact getdate() values for different rows.
This doesn't occur with each entry either, it is randomly occurring in the application.
select #formHeaderId=stage2_checklist_header_id
from stage2_checklist_header
where environmental_forms_id=#envFormId
and checklist_monthyear=#inspected_month
order by start_date desc
if #formHeaderId = 0 begin
insert into stage2_checklist_header(
environmental_forms_id
,start_date
,checklist_monthyear
,st2h_load_date )
values( #envFormId
,#check_date
,#inspected_month
,getdate())
set #formHeaderId = scope_identity()
print 'inserted new header record ' + cast(#formHeaderId as varchar(50))
end
IF (NOT EXISTS(
SELECT *
FROM stage2_checklist_detail
WHERE stage2_checklist_header_id = #formHeaderId
AND check_date = #check_date
))
INSERT INTO stage2_checklist_detail
(stage2_checklist_header_id, check_date, st2_chk_det_load_date,
inspected_by)
VALUES
(#formHeaderId, #check_date, GETDATE(), #inspected_by)
SET #form_detail_id = SCOPE_IDENTITY()
PRINT 'inserted detail record ' + CAST(#form_detail_id AS VARCHAR(50))
Here is a similar case where the developer was able to track the duplicate entries to simultaneous calls from different spids (which sidestepped the EXISTS check). After experimenting with isolation levels and transactions - and trying to avoid deadlocks - it sounds like the solution in that case was to use sp_getapplock and sp_releaseapplock.
In the NOT EXISTS check, you are looking for records that have both the same ID and the same date. So, if the combination of ID AND date does not exist in the table, the row will be inserted.
In your description of the problem you state "All of the data is exactly the same except for the id". The ID being different will always cause an INSERT based on the logic you are using to check for existence.

Print a report Multiple times, (SSRS reporting services)

I am currently working on SSRS reports 2008 displaying them in Website created in VS 2010 i.e., ASP.NET 4.0 C#.
My current issue is I have a report with only a Letterhead on it. And this report page needs to be printed multiple times based on the value in number of pages TextBox as shown
To be a bit descriptive: When the user enters the value in Number of Pages TextBox and clicks on this Print button icon, he/she lands on the page with ReportViewer control on it, displaying the report.This report has only a letterhead in the PageHeader of the report and here this report will be printed by clicking the default print button of ReportViewer control. But, I am unable to figure out, how to print this report page as many times as there will be the value in the No of Pages TextBox (as shown in the fig.)
(The Letterhead of the company to be shown in report is retrieved from database through a Stored Procedure)
I tried a lot of Googling but to no avail.
Create a new report.
This report should have 1 parameter called "number of copies" (or equivalent).
It should also have a Tablix with 1 column and no borders, inside the cell insert a sub report pointing to the report with the letterhead.
Your dataset query should be something like this:
WITH dataset AS (
SELECT 1 AS ID UNION ALL
SELECT ID + 1 FROM dataset WHERE ID < #Param
)
SELECT ID
FROM dataset --edit: obviously I was missing the table
OPTION (MAXRECURSION 0)
Then on your tablix, use this dataset, group by ID and on the group properties select "Page Breaks"->"Between each instance of a group".
If I understood your question correctly, this should do the trick.
Expanding on Joao's solution (thanks for that) you can also do it without a subreport by joining the counter table to the actual data you want to display in the dataset.
Add a Copies integer parameter with a default value of 1
Update your dataset to include the counter and join
-- Generate a table with #Count rows
WITH dataset AS (SELECT 1 AS Copy UNION ALL SELECT Copy + 1 AS Expr1 FROM dataset AS dataset_2 WHERE (Copy < #Copies))
SELECT * FROM dataset INNER JOIN (
-- The primary data to repeat
SELECT * FROM MyTable WHERE Id = #IdParam
-- End
) d ON 1=1 OPTION (MAXRECURSION 0)
Add/update your row group to group on [Copy]
Set the row group page breaks to 'between each instance'

Column 'AuctionStatus' cannot be used in an IF UPDATE clause because it is a computed column

I am developing an Auction site in asp.net3.5 and sql server 2008R2, My Database has an Auction Table that has a calculated column "AuctionStatus" -
(case when [EndDateTime] < getdate() then '0' else '1' end)
that gives auction status Active or inactive based on End Date.
Now I want to call a stored procedure that sends email notifications to buyers and sellers as soon as AuctionStatus becomes '0'. For that i tried to create a after update trigger that could call the email notification sp, but i am not able to do so.
I am getting the following error message :-
Msg 2114, Level 16, State 1, Procedure trgAuctionEmailNotification,
Line 6 Column 'AuctionStatus' cannot be used in an IF UPDATE clause
because it is a computed column.
The trigger is:
CREATE TRIGGER trgAuctionEmailNotification ON SE_Auctions
AFTER UPDATE
AS
BEGIN
IF (UPDATE (AuctionStatus))
BEGIN
IF EXISTS (SELECT * FROM inserted WHERE currentbidderid > 0
AND AuctionStatus='0' )
BEGIN
DECLARE #ID int
SELECT #ID = AuctionID from inserted
EXEC spSelectSE_AuctionsByAuctionID #ID
END
END
END
You could just replace AuctionStatus with the corresponding expression :
IF EXISTS (SELECT * FROM inserted WHERE currentbidderid > 0 AND [EndDateTime] < getdate() )
But, the point is I don't see how your trigger will be "triggered" as [AuctionStatus] is never "updated". Its Value is just calculated whenever you need it.
You could go for a sql job that runs every x minutes and send a notification for each auction which ended during the last x minutes.
You need to add a real column containing a flag to indicate whether the notifications have been sent, and then implement a polling technique to scan the table for rows where the status is inactive and notifications haven't been sent.
The computed column doesn't really transition from one state to another, so it's not like an UPDATE has occurred. Even if SQL Server did implement this, it would be hideously expensive, since it would have to query the entire table for transitioning rows every 3ms. (or even more frequently if you're using datetime2 with a higher precision)
Whereas you can pick a suitable polling interval yourself. This could be an SQL agent job, or in some service code somewhere, whatever best fits the rest of your architecture.

Resources