Passing SSRS Dataset Parameters on the fly - sql-server

I have a SSRS 2008 tabular report with a drill down group by. The group by is the AssignedAnalystId. In the Database and server only the AssignedAnalystId is available. I have another database on another server that has the table with the mapping between the AssignedAnalystId and there actual name (Full User Name).
What I want to do is to be able to pass in the AssignedAnalystId on the fly to the other dataset as if it were a scalar function and get the full username to show in the group instead of the AssignedAnalystId. Is there a way to do this?

Ideally, you would want to join the tables in your initial query, but you can have two separate datasets in your report and use the Lookup function to do what you need. The Lookup function takes 4 parameters; in your case you would fill in: ID field from the 1st dataset, ID field from the second dataset, username field from the second dataset, the name of the dataset. See the MSDN article for more info: http://msdn.microsoft.com/en-us/library/ee210531.aspx
A good way to filter your data is to use a Split function. Set your SSRS parameter to be comma separated values or even multi-valued and then you can use the table-valued function below to turn it into a temp table for use in your query:
CREATE FUNCTION Split (#origString varchar(max))
returns #temptable TABLE (items varchar(max))
as
begin
declare #idx int
declare #split varchar(max)
set #idx = 1
if datalength(#origString )<1 or #origString is null
return
while #idx <> 0
begin
set #idx = charindex(',', #origString)
if #idx <> 0
set #split = left(#origString, #idx - 1)
else
set #split = #origString
if(datalength(#split) > 0)
insert into #temptable(Items) values(ltrim(rtrim(#split)))
set #origString = right(#origString, datalength(#origString) - #idx)
if datalength(#origString) = 0
break
end
return
end
Then your query could would include something like this to act as a filter:
SELECT *
FROM Table1 as T1
INNER JOIN Split(#SSRScsvParameter) as T2 on T1.ID = T2.ID

Related

Show a few columns in a stored procedure based on a parameter

I have a parameter in my stored procedure called internal. If "internal" = yes then I want to display an additional 2 columns in my results. If it's no I don't want to display these columns.
I can do a case statement and then I can set the column to be empty but the column name will still be returned in the results.
My questions are:
Is there a way not to return these 2 columns in the results at all?
Can I do it in one case statement and not a separate case statement for each column?
Thank you
No, CASE is a function, and can only return a single value.
And According to your comment:-
The issue with 2 select statements are that it's a major complicated
select statement and I really don't want to have to have the whole
select statement twice.
so you can use the next approach for avoid duplicate code:-
Create procedure proc_name (#internal char(3), .... others)
as
BEGIN
declare #AddationalColumns varchar(100)
set #AddationalColumns = ''
if #internal = 'Yes'
set #AddationalColumns = ',addtionalCol1 , addtionalCol2'
exec ('Select
col1,
col2,
col3'
+ #AddationalColumns +
'From
tableName
Where ....
' )
END
Try IF Condition
IF(internal = 'yes')
BEGIN
SELECT (Columns) FROM Table1
END
ELSE
BEGIN
SELECT (Columns With additional 2 columns) FROM Table1
END
You can do something like this solution. It allows you to keep only one copy of code if it's so important but you will have to deal with dynamic SQL.
CREATE TABLE tab (col1 INT, col2 INT, col3 INT);
GO
DECLARE #internal BIT = 0, #sql NVARCHAR(MAX)
SET #sql = N'SELECT col1 ' + (SELECT CASE #internal WHEN 1 THEN N', col2, col3 ' ELSE N'' END) + N'FROM tab'
EXEC sp_executesql #sql
GO
DROP TABLE tab
GO
Another option is to create a 'wrapper' proc. Keep your current one untouched.
Create a new proc which executes this (pseudo code):
create proc schema.wrapperprocname (same #params as current proc)
as
begin
Create table #output (column list & datatypes from current proc);
insert into #output
exec schema.currentproc (#params)
if #internal = 'Yes'
select * from #output
else
select columnlist without the extra 2 columns from #output
end
This way the complex select statement remains encapsulated in the original proc.
Your only overhead is keeping the #output table & select lists in in this proc in sync with any changes to the original proc.
IMO it's also easier to understand/debug/tune than dynamic sql.

SSRS Reporting - Multiple Selections Defining Multiple Queries

An SSRS dataset has two T-SQL queries. One query will only run if a certain parameter has two or more values selected. The other query will only run if the parameter has only one value selected. How can I let the dataset know whether one value or multiple values were selected from the parameter?
You can create an addional integer parameter called NumberOfValues, set it to be hidden and use an expression like the below in the Default Value:
=Parameter!YourMultipleValueParam.Value.Count
Then in the dataset you can use the NumberOfValues parameter to determine the number of values selected in YourMultipleValueParam parameter.
IF #NumberOfValues > 1 BEGIN ....
Good question. Here's one way I've found around this.
Step 1: In your dataset's properties, go to the "Parameters" tab. Add a parameter with the following expression, replacing MyParameterName with your parameter's name.
=join(Parameters!MyParameterName.Value,",")
Step 2: If you don't already have one, add a splitting function to your SQL Server functions. Simple google search would direct you to something like this: Split function equivalent in T-SQL?
Step 3: Select a count of parameters used in your SSRS report. Based on the result, do what is desired: (My splitting function is simply called Split)
IF (select count(*) from Devl.dbo.Split(#MyParameterName,',')) = 1
BEGIN
/* Do your second query here, when one parameter is selected */
END
IF (select count(*) from Devl.dbo.Split(#MyParameterName,',')) > 1
BEGIN
/* Do your first query here, when more than one parameter is selected */
END
EDIT: Alternatives to steps 2 and 3 if you don't want to (or can't) create/utilize a split function.
Step 2: In your main query at the top, include the following (basically an in-line version of a split function)
declare #string varchar(max), #delimiter char(1)
declare #temptable table (items varchar(max))
set #string = #MyParameterName
set #delimiter = ','
declare #idx int, #slice varchar(max)
select #idx = 1
if len(#String)<1 or #String is null return
while #idx!= 0
begin
set #idx = charindex(#Delimiter,#String)
if #idx!=0
set #slice = left(#String,#idx - 1)
else
set #slice = #String
if(len(#slice)>0)
insert into #temptable(Items) values(#slice)
set #String = right(#String,len(#String) - #idx)
if len(#String) = 0 break
end
Step 3: Select a count of parameters used in your SSRS report. Based on the result, do what is desired: (My splitting function is simply called Split)
IF (select count(*) from #temptable) = 1
BEGIN
/* Do your second query here, when one parameter is selected */
END
IF (select count(*) from #temptable) > 1
BEGIN
/* Do your first query here, when more than one parameter is selected */
END

Transfer data from one SQL Server table to another

For example I have one SQL Server database that contains a table
Id Address
1 England,London,someaddress
2 Germany,Berlin,someaddress2
And I have another SQL Server database that contains following table with scheme
Id Country City Address
I need transfer data from first database to second. Like this.
id Country City Address
1 England London someaddress
2 Germany Berlin someaddress2
How can I do that?
You can do that by creating a User Define Function that detect Country , City, Address by Splitting and than insert into second table.
Split Function :
CREATE FUNCTION [dbo].[Split](#String varchar(8000), #Delimiter char(1))
returns #temptable TABLE (id int , items varchar(8000))
as
begin
declare #idx int
declare #id int
declare #slice varchar(8000)
set #id = 1
select #idx = 1
if len(#String)<1 or #String is null return
while #idx!= 0
begin
set #idx = charindex(#Delimiter,#String)
if #idx!=0
set #slice = left(#String,#idx - 1)
else
set #slice = #String
if(len(#slice)>0)
begin
insert into #temptable(id, Items) values( #id , #slice)
set #id = #id + 1
end
set #String = right(#String,len(#String) - #idx)
if len(#String) = 0 break
end
return
end
then use in Insert Query like this :
INSERT INTO NewTbl
SELECT .... ,
(SELECT ITEMS FROM dbo.Split(Address) where id = 1) as Country,
(SELECT ITEMS FROM dbo.Split(Address) where id = 2) as City,
(SELECT ITEMS FROM dbo.Split(Address) where id = 3) as Address,
...
There are a few ways to actually move the data.
1.) Linked Server http://msdn.microsoft.com/en-us/library/ms188279.aspx
2.) OpenRowSet http://msdn.microsoft.com/en-us/library/ms190312.aspx
3.) Replication http://msdn.microsoft.com/en-us/library/ms151198.aspx
Depending on your needs you need to choose the best one for you.
If you want the data from your second database to be accessable in your original databse, in the same way as it's own data, for queries, stored procedures...etc have a look at Linked Servers.
If you want a one off access to data have a look at OpenRowSet.
If you have the same table on both databases and want to keep that data in sync automatically I would look at Replication. You can set up your own replication stored procedures that can perform custom logic, like the split.
You then can impliment the split as noted in the other answer to split your data.
If you want to copy data from one server to another database server .then you must make linked server between them.
and execute like following query.
insert into [127.234.11.50].[cgwssitws].dbo.tbl_ws_hotelier(paramid,hotelid,paramname,paramvalue)
select paramid,hotelid,paramname,paramvalue from [126.32.22.30].[CGWS_Hotel].dbo.tbl_param where hotelid='22'

Duplicate Auto Numbers generated in SQL Server

Be gentle, I'm a SQL newbie. I have a table named autonumber_settings like this:
Prefix | AutoNumber
SO | 112320
CA | 3542
A whenever a new sales line is created, a stored procedure is called that reads the current autonumber value from the 'SO' row, then increments the number, updates that same row, and return the number back from the stored procedure. The stored procedure is below:
ALTER PROCEDURE [dbo].[GetAutoNumber]
(
#type nvarchar(50) ,
#out nvarchar(50) = '' OUTPUT
)
as
set nocount on
declare #currentvalue nvarchar(50)
declare #prefix nvarchar(10)
if exists (select * from autonumber_settings where lower(autonumber_type) = lower(#type))
begin
select #prefix = isnull(autonumber_prefix,''),#currentvalue=autonumber_currentvalue
from autonumber_settings
where lower(autonumber_type) = lower(#type)
set #currentvalue = #currentvalue + 1
update dbo.autonumber_settings set autonumber_currentvalue = #currentvalue where lower(autonumber_type) = lower(#type)
set #out = cast(#prefix as nvarchar(10)) + cast(#currentvalue as nvarchar(50))
select #out as value
end
else
select '' as value
Now, there is another procedure that accesses the same table that duplicates orders, copying both the header and the lines. On occasion, the duplication results in duplicate line numbers. Here is a piece of that procedure:
BEGIN TRAN
IF exists
(
SELECT *
FROM autonumber_settings
WHERE autonumber_type = 'SalesOrderDetail'
)
BEGIN
SELECT
#prefix = ISNULL(autonumber_prefix,'')
,#current_value=CAST (autonumber_currentvalue AS INTEGER)
FROM autonumber_settings
WHERE autonumber_type = 'SalesOrderDetail'
SET #new_auto_number = #current_value + #number_of_lines
UPDATE dbo.autonumber_settings
SET autonumber_currentvalue = #new_auto_number
WHERE autonumber_type = 'SalesOrderDetail'
END
COMMIT TRAN
Any ideas on why the two procedures don't seem to play well together, occasionally giving the same line numbers created from scratch as lines created by duplication.
This is a race condition or your autonumber assignment. Two executions have the potential to read out the same value before a new one is written back to the database.
The best way to fix this is to use an identity column and let SQL server handle the autonumber assignments.
Barring that you could use sp_getapplock to serialize your access to autonumber_settings.
You could use repeatable read on the selects. That will lock the row and block the other procedure's select until you update the value and commit.
Insert WITH (REPEATABLEREAD,ROWLOCK) after the from clause for each select.

Can I send array of parameter to store procedure?

I have User table, it has UserId uniqueidentifier, Name varchar and IsActive bit.
I want to create store procedure to set IsActive to false for many user, for example, if I want to deactive 2 users, I want to send Guid of those users to store procedure (prefer as array). I want to know how can I do it?
P.S. I'm working on Microsoft SQL Azure
Along the same lines than Elian, take a look at XML parameters. Generally speaking you should have a cleaner/safer implementation using xml than parsing a list of strings. Click here for a code example
Here is a solution I used a while ago and that was working fine.
Send the list of guid you want to deactive merged into a comma separated string to the sp.
Then in the sp, you first convert this string into a table thanks to a table-valued function.
Here is a sample with bigint, but you can easily modify it so that it works with guid
Step 1 : the table-valued function
CREATE FUNCTION [dbo].[BigIntListToTable] (
#list VARCHAR(max)
)
RETURNS
#tbl TABLE
(
nval BIGINT NOT NULL
) AS
BEGIN
DECLARE #nPos INT
DECLARE #nNextPos INT
DECLARE #nLen INT
SELECT #nPos = 0, #nNextPos = 1
WHILE #nNextPos > 0
BEGIN
SELECT #nNextPos = CHARINDEX(',', #list, #nPos + 1)
SELECT #nLen = CASE WHEN #nNextPos > 0
THEN #nNextPos
ELSE LEN(#list) + 1
END - #nPos - 1
INSERT #tbl (nval)
VALUES (CONVERT(BIGINT, SUBSTRING(#list, #nPos + 1, #nLen)))
SELECT #nPos = #nNextPos
END
RETURN
END
Step 2 : the stored proc
CREATE PROCEDURE [dbo].[spMySP]
#IdList VARCHAR(max)
AS
BEGIN
SET NOCOUNT ON;
SET ROWCOUNT 0
UPDATE dbo.YourTable
SET isActive = 0
FROM dbo.YourTable
INNER JOIN dbo.BigIntListToTable(#IdList) l
ON dbo.YourTable.id = l.nval
END

Resources