SSRS with custom paging - ssrs-2008

I am working on a SQL Server report which shows the data of size 300 K and therefore it is very slow most of the time is spent on the report processing. So I m thinking if I can do some program to get the data from the database per page. This way call from the db and report processing time will reduce. So in other words if I am showing 50 records per page and when I am on page one and click on page 2 or the next button, my report get the data from 51 to 100. When I click on the next button again then I get the data for page 3 which would be 101 to 150.
So is there any way I can achieve.

Usually when the report is rendered all the data is pulled and SSRS renders the report which causes delay. If performance is the key here, you could use a stored procedure to retrieve 50 rows at a time, instead of passing all the values directly to SSRS - caveat here is you wont be able to use the native next/previous page buttons for this.
A work around is to create custom links to loop back to the report itself with incremented parameters specifying an index row to start from.
Create a stored procedure that takes in a parameter which specifies the starting row from your table:
CREATE PROCEDURE dbo.usp_GetData
#RowNumber BIGINT
AS
BEGIN
DECLARE #FirstRow BIGINT
DECLARE #LastRow BIGINT
SET #FirstRow = #RowNumber
SET #LastRow = #RowNumber + 50
;WITH CTE AS
(
SELECT *,
ROW_NUMBER() OVER (ORDER BY num) AS RowNumber
FROM dbo.TestTable
)
SELECT *
FROM CTE
WHERE RowNumber >= #FirstRow
AND RowNumber < #LastRow
END
GO
Create a stored procedure that retrieves the total rows from your table:
CREATE PROCEDURE dbo.usp_GetTotalRows
AS
BEGIN
SELECT COUNT(*) "TotalRows"
FROM dbo.TestTable
END
GO
Create the report and add the two datasets using the two stored procedures.
The #RowNumber parameter should be automatically generated. You can set the default value to 1 to start the report from row 1.
Create two "custom" buttons on the report (effectively just links back to the same report). You could use text boxes for Previous/Next Page buttons.
For the "Previous Button" Text Box - Properties > Action > Go to report > Specify a report (select the name of your report name). Add Parameter and set the expression to:
=Parameters!RowNumber.Value-50
For the "Next Button" Text Box - Properties > Action > Go to report > Specify a report (select the name of your report name). Add Parameter and set the expression to:
=Parameters!RowNumber.Value+50
You can also change the visibility options for the buttons (such as hiding "Previous Page" button when Parameters!RowNumber.Value = 1, or hiding the "Next Page" button when Parameters!RowNumber.Value + 50 >= DataSetName!TotalRows.Value)

Related

Substring to divide and update a field in the same syntax

sorry in advance if my question is already exists.
I'm a sql beginner and have an issue about how can i update a field with 'Select' where one field already exists in the datatable (Table1) and the another field update by the sintax.
Select
Business,
Month,
Opens
From Table2
I would like in the same syntax to be able to do the sends / opens calculation and update the field named 'Open Rate'
example
Today i have the table1 with
Month -- Send -- Opens -- Open Rate
May -- 100 -- --
The table 2 have
Opens - Month
5 -- May
My goal: update the table 1 with the table 2 with the open rate (Send/Opens):
Month -- Send -- Opens -- Open Rate
May -- 100 -- 5 -- 20

historical result of SELECT statement

I want to query a large number of rows and displayed to the user, however the user will see only for example 10 rows and I will use LIMIT and OFFSET, he will press 'next' button in the user interface and the next 10 rows will be fetched.
The database will be updated all the time, is there any way to guarantee that the user will see the data of the next 10 rows as they were in the first select, so any changes in the data will not be reflected if he choose to see the next 10 rows of result.
This is like using SELECT statement as a snapshot of the past, any subsequent updates after the first SELECT will not be visible for the subsequent SELECT LIMIT OFFSET.
You can use cursors, example:
drop table if exists test;
create table test(id int primary key);
insert into test
select i from generate_series(1, 50) i;
declare cur cursor with hold for
select * from test order by id;
move absolute 0 cur; -- get 1st page
fetch 5 cur;
id
----
1
2
3
4
5
(5 rows)
truncate test;
move absolute 5 cur; -- get 2nd page
fetch 5 cur; -- works even though the table is already empty
id
----
6
7
8
9
10
(5 rows)
close cur;
Note that it is rather expensive solution. A declared cursor creates a temporary table with a complete result set (a snapshot). This can cause significant server load. Personally I would rather search for alternative approaches (with dynamic results).
Read the documentation: DECLARE, FETCH.

Two filters on one column with respect to each other

I would like to filter my data source by itself. In SQL it is just INNER JOINNING a table by itself.
For example,
SELECT table1.*
FROM table1 INNER JOIN (SELECT id FROM table1 WHERE variable = ‘X’ AND value = 1) q1 ON table1.id = q1.id
WHERE table1.variable = ‘Y’
As you can see I want to present only the variable which equals ‘Y’ with respect to variable =’X’ and value=1.
I can also write it like this,
SELECT *
FROM table1
WHERE variable = ‘Y’ AND id IN (SELECT id FROM table1 WHERE variable = ‘X’ AND value = 1)
I am using a long data file which means my primary key is 'id' and 'variable' together. So, I want all the variable = ‘Y’ data to be presented only if the 'id' has variable = ‘X’ AND value = 1. How do I translate this process in Tableau dashboard?
Any suggestions on how to do it without inner joining the data source by itself? I tried the inner join way but my data is very large which resulting in too much processing time and it makes all the other processes extremely slow.
First, just point your data source at table1 without any other changes. Plain and simple.
Second, back on a worksheet, select the id field in the datapane and right click to create a set. Choose the all radio button on the general tab of the set dialog pane, and then switch to the condition tab. Define the set via the formula max(variable = 'x' and value = 1). Call your set something meaningful like ids_having_an_X1. This will create a set of ids that have at least one data row matching your condition. Think of it as a list of ids that could go inside a SQL IN (...) clause if that helps
Now you can use your set on the filter shelf to only include those ids in the query, or in calculations, or on other shelves.
To get the effect of your where clause, put variable on the filter shelf choosing only the value 'Y'

Get the value of visible column of JasperReports Server input control?

I have a report in JasperReports Server 5.2.0, in this report I have two input control
first one is:
COUNTRY (value column- COUNTRY_ID, visible column- COUNTRY_NAME)
and another one is
STATES (value column- STATE_ID and visible column - STATE_NAME).
These two parameters I am passing to the report, now at the end of the report I want to show the input parameter selection value so user can see what he has selected. But I am not able to get the visible values of parameters. I can print only value column value.
So my question is there any way to print the visible column values of input control in reports?
Till now , Visible Columns are not passed,where Value Columns are passed to Jrml File in Jasper.
To answer you question There is a way to print the visible column values.
It can be done using Sub-queries, by using 'Value Column' passed to the JRML file.
Then add the subquery to your main query and it`s done!!
In the above scenario You can display
State Name
SELECT States.STATE_NAME from States WHERE state_id = $P{STATE_ID} - If it is Single Select input control
SELECT GROUP_CONCAT(States.STATE_NAME) from States WHERE state_id = $X{IN,state_id,STATE_ID} - If it is Multi-Select input control
Country Name
SELECT Country.COUNTRY_NAME from COUNTRY WHERE country_id= $P{COUNTRY_NAME} - If it is Single Select input control
SELECT GROUP_CONCAT(Country.COUNTRY_NAME) from COUNTRY WHERE country_id = $X{IN,state_id,STATE_ID} - If it is Multi-Select input control
Suppose this your main query where Country and State are missing..
SELECT
`id`,
`product-id`,
`name`,
`description`,
`branch`,
`stock`,
`price`
FROM
`products`
WHERE
`name` LIKE "%car%"
The modified query will looks like..
SELECT
`id`,
`product-id`,
`name`,
`description`,
`branch`,
`stock`,
`price`,
(SELECT States.STATE_NAME from States WHERE state_id = $P{STATE_ID}) as state,
(SELECT Country.COUNTRY_NAME from COUNTRY WHERE country_id=P{COUNTRY_NAME}) as country
FROM
`products`
WHERE
`name` LIKE "%car%"

Select only half the records

I am trying to figure out how to select half the records where an ID is null. I want half because I am going to use that result set to update another ID field. Then I am going to update the rest with another value for that ID field.
So essentially I want to update half the records someFieldID with one number and the rest with another number splitting the update basically between two values for someFieldID the field I want to update.
In oracle you can use the ROWNUM psuedocolumn. I believe in sql server you can use TOP.
Example:
select TOP 50 PERCENT * from table
You can select by percent:
SELECT TOP 50 PERCENT *fields* FROM YourTable WHERE ...
update x set id=#value from (select top 50 percent * from table where id is null) x
The following SQL will return the col_ids of the first half of the table.
SELECT col_id FROM table
WHERE rownum <= (SELECT count(col_id)/2 FROM table);
If the total number of col_ids is an odd number then you will get the first half - 1. This is because, for instance, we have 51 total records, the count(col_id)/2 returns 25.5, and since there is no rownum equal to this result, we get everything equal to 25 and below. That means the other 26 are not returned.
However, I have not seen the reverse statement working:
SELECT col_id FROM table
WHERE rownum > (SELECT count(col_id)/2 FROM table);
So if you want the other half of the table, you could just store the first results into a temp table, lets call it TABLE_A. Then just do MINUS on the original table from this table:
SELECT col_id FROM table
MINUS
SELECT col_id FROM table_a
Hopefully this helps someone.