SSRS 2005 passing parameters to SQL Server 2000 stored procedure - tsql

Below is code that I built from an example I found online, I can't find the link, but the code is referenced in the answers on this stack overflow question: Passing multiple values for a single parameter in Reporting Services.
Here is the SQL code I am working with right now within my stored procedure, it was a long procedure so I summed it down to just the section I am working on, and added the DECLARE and SET for #EMPLOYEES, which are passed as a parameter from SSRS to make the code snippet run.
DECLARE #EMPLOYEES varchar(8000)
-- EMPLOYEES is a comma separated list of EMPLOYEE IDS
-- FROM SSRS Report Parameters. Each ID is 12 characters
-- And there are 806 Employees to choose from, which
-- when all are selected, the Comma separated string grows
-- to 11,193 characters, much longer than 8000
SET #EMPLOYEES = 'EMP000000001,EMP000000002,EMP000000003'
CREATE TABLE #EMPLOYEEIDS
(
EMPLOYEEID varchar(100) NOT NULL
)
DECLARE #CharIndex AS int
DECLARE #Piece AS varchar(100)
-- FILL THE #EMPLOYEEIDS TABLE WITH THE COMMA SEPARATED EMPLOYEE IDS
SELECT #CharIndex = 1
WHILE #CharIndex > 0 AND LEN(#EMPLOYEES) > 0
BEGIN
SELECT #CharIndex = CHARINDEX(',', #EMPLOYEES)
IF #CharIndex > 0
SELECT #Piece = LEFT(#EMPLOYEES, #CharIndex - 1)
ELSE
SELECT #Piece = #EMPLOYEES
INSERT INTO #EMPLOYEEIDS (EMPLOYEEID) VALUES (#Piece)
SELECT #EMPLOYEES = RIGHT(#EMPLOYEES, LEN(#EMPLOYEES) - #CharIndex)
END
SELECT * FROM #EMPLOYEEIDS
DROP TABLE #EMPLOYEEIDS
I had 6 sets of multi-values, all of them worked fine, until I found that the reports were missing much of the data for employees, to which I found that the VARCHAR(8000) was overflowed when selecting all the employees on the report parameters (there are over 800 of them). The Report would run, SQL would happily truncate the VARCHAR to 8000 characters, and a quarter of the IDS were not parsed.
So I tried to switch the VARCHAR to a text field, and none of the parsing functions would work when the field is set up as TEXT. I get errors like the following:
Msg 8116, Level 16, State 2, Procedure usp_QualityMonitoring_AllProfiles_SelectWithParameters, Line 89
Argument data type text is invalid for argument 1 of left function.
This is understandable, I know that many functions that work with VARCHAR will not work with TEXT. So, SQL is truncating everything after 8000 characters when I use a VARCHAR, and the procedure won't ever run if I switch it to TEXT.
What other options to I have to pass multi-valued parameters from SSRS to a SQL Server stored procedure that can support this many options?
OR is there a way to fix the code in the stored procedure to parse through TEXT instead of VARCHAR?
Note: I originally thought the SQL Server running the Stored Proc was 2005, but I have determined that it is not:
SELECT ##VERSION
-- Microsoft SQL Server 2000 - 8.00.2039 (Intel X86) May 3 2005 23:18:38 Copyright (c) 1988-2003 Microsoft Corporation Standard Edition on Windows NT 5.2 (Build 3790: Service Pack 2)

Related

SQL Command to insert Chinese Letters

I have a database with one column of the type nvarchar. If I write
INSERT INTO table VALUES ("玄真")
It shows ¿¿ in the table. What should I do?
I'm using SQL Developer.
Use single quotes, rather than double quotes, to create a text literal and for a NVARCHAR2/NCHAR text literal you need to prefix it with N
SQL Fiddle
Oracle 11g R2 Schema Setup:
CREATE TABLE table_name ( value NVARCHAR2(20) );
INSERT INTO table_name VALUES (N'玄真');
Query 1:
SELECT * FROM table_name
Results:
| VALUE |
|-------|
| 玄真 |
First, using NVARCHAR might not even be necessary.
The 'N' character data types are for storing data that doesn't 'fit' in the database's defined character set. There's an auxiliary character set defined as the NCHAR Character set. It's kind of a band aid - once you create a database it can be difficult to change its character set. Moral of this story - take great care in defining the Character Set when creating your database and do not just accept the defaults.
Here's a scenario (LiveSQL) where we're storing a Chinese string in both NVARCHAR and VARCHAR2.
CREATE TABLE SO_CHINESE ( value1 NVARCHAR2(20), value2 varchar2(20 char));
INSERT INTO SO_CHINESE VALUES (N'玄真', '我很高興谷歌翻譯。' )
select * from SO_CHINESE;
Note that both the character sets are in the Unicode family. Note also I told my VARCHAR2 string to hold 20 characters. That's because some characters may require up to 4 bytes to be stored. Using a definition of (20) would give you only room to store 5 of those characters.
Let's look at the same scenario using SQL Developer and my local database.
And to confirm the character sets:
SQL> clear screen
SQL> set echo on
SQL> set sqlformat ansiconsole
SQL> select *
2 from database_properties
3 where PROPERTY_NAME in
4 ('NLS_CHARACTERSET',
5 'NLS_NCHAR_CHARACTERSET');
PROPERTY_NAME PROPERTY_VALUE DESCRIPTION
NLS_NCHAR_CHARACTERSET AL16UTF16 NCHAR Character set
NLS_CHARACTERSET AL32UTF8 Character set
First of all, you should to establish the Chinese character encoding on your Database, for example
UTF-8, Chinese_Hong_Kong_Stroke_90_BIN, Chinese_PRC_90_BIN, Chinese_Simplified_Pinyin_100_BIN ...
I show you an example with SQL Server 2008 (Management Studio) that incorporates all of this Collations, however, you can find the same characters encodings in other Databases (MySQL, SQLite, MongoDB, MariaDB...).
Create Database with Chinese_PRC_90_BIN, but you can choose other Coallition:
Select a Page (Left Header) Options > Collation > Choose the Collation
Create a Table with the same Collation:
Execute the Insert Statement
INSERT INTO ChineseTable VALUES ('玄真');

Turn T-SQL TOP on or off by parameter via PowerShell

Is it possible to send a parameter into a powershell sql command (using invoke-sqlcmd) which will either select ALL rows of a query OR just the top 5?
e.g.
SELECT TOP $(rowCount) FROM MyTable
I wan't to be able to effectively turn on/off this selection in the script. I thought PERCENTAGE would work but I only want to select 5 rows and PERCENTAGE would return too many as I am dealing with data-sets consisting of 10s rows and also millions of rows.
I would like to run this script from PowerShell and also in SQL management studio without it complaining about the semantics, but it doesn't seem to like the $() syntax.
The value used in the top can already be made dynamic in vanilla sql:
declare #t table (i int);
insert into #t values(1), (1), (2), (3), (1), (2);
declare #n bigint = 2;
select top (#n) *
from #t;
set #n = 9223372036854775807; -- Max value available in a BIGINT
select top (#n) *
from #t;

Numeric literals in sql server 2008

What is the type that sql server assigns to the numeric literal: 2. , i.e. 2 followed by a dot?
I was curious because:
select convert(varchar(50), 2.)
union all
select convert(varchar(50), 2.0)
returns:
2
2.0
which made me ask what's the difference between 2. and 2.0 type wise?
Sql server seems to assign types to numeric literals depending on the number itself by finding the minimal storage type that can hold the number. A value of 1222333 is stored as int while 1152921504606846975 is stored as big int.
thanks
Edit: I also want to add why this is so important. In sql server 2008 r2, select 2/5 returns 0 while select 2./5 returns 0.4, due to the way sql server treats these types. In oracle and Access select 2/5 (oracle: select 2/5 from dummy) returns 0.4. That's the way it should be. I wonder if they fixed this behaviour in sql server 2012. I would be surprised if they did.
This script might answer my question. The type of 2. is numeric(1, 0).
create table dbo.test_type (field sql_variant)
go
delete from dbo.test_type
go
INSERT INTO dbo.test_type
VALUES (2.);
INSERT INTO dbo.test_type
VALUES (2.0);
SELECT field
, sql_variant_property (field
, 'BaseType')
AS BaseType
, sql_variant_property (field
, 'Precision')
AS Precision
, sql_variant_property (field
, 'Scale')
AS Scale
FROM dbo.test_type
It returns:
2 numeric 1 0
2.0 numeric 2 1
This is why when 2.0 is converted to varchar the result is 2.0. Sql server seems to record the precision.

Cannot use text, ntext, or image in a trigger

Using SQL server 2008 R2, I'm getting the error:
Msg 311, Level 16, State 1, Procedure ad_user, Line 28
Cannot use text, ntext, or image columns in the 'inserted' and 'deleted' tables.
The purpose of the trigger is to update a user-group table when a new user is inserted. I've only included the SQL up to where the error occurs.). What confuses me is if I remove one of the integer declarations, I don't get the same error (just errors about not having declared the variable).
CREATE trigger [dbo].[ad_user] on [dbo].[tps_user]
FOR INSERT
AS
DECLARE #UserGuid uniqueidentifier
DECLARE #EndUserTypeGuid uniqueidentifier
DECLARE #UserTypeGuid uniqueidentifier
DECLARE #saGuid uniqueidentifier
DECLARE #GroupGuid uniqueidentifier
DECLARE #NewUser VarChar(250)
DECLARE #deptnum VarChar(250)
DECLARE #locnum VarChar(250)
DECLARE #CN VarChar(250)
DECLARE #NewOU VarChar(250)
DECLARE #pos1 integer
DECLARE #pos2 integer
BEGIN
SELECT #EndUserTypeGuid=tps_guid FROM tps_user_type WHERE tps_name='EndUser'
SELECT #saGuid = tps_guid FROM tps_user WHERE tps_title = 'SA'
SELECT #UserGuid=tps_guid,
#UserTypeGuid=tps_user_type_guid,
#NewUser=tps_title,
#deptnum=usr_departmentnumber,
#locnum=usr_locationnumber,
#CN=usr_ou
FROM inserted
IF #UserTypeGuid=#EndUserTypeGuid
BEGIN
SELECT #GroupGuid=tps_guid FROM tps_group WHERE usr_departmentnumber=#deptnum
IF #GroupGuid IS NOT NULL
BEGIN
IF #UserGuid NOT IN (SELECT tps_user_id
FROM tps_user_group WHERE tps_group_id = #GroupGuid)
BEGIN
-- Remove the user from other groups
DELETE FROM tps_user_group WHERE tps_user_id = #UserGuid;
-- Create Customer Group Membership from department
INSERT INTO tps_user_group(tps_user_id, tps_group_id, tps_creation_user_guid,
tps_last_update_user_guid, tps_creation_date, tps_last_update)
VALUES(#UserGuid, #GroupGuid, #saGuid, #saGuid, GetDate(), GetDate());
END
END
END
END
I have tested this and this error message will come at compile time, not at runtime, when you explicitly reference such a column in the inserted / deleted pseudo-tables. Unfortunately I think you will have to correct these columns in the underlying table in order to use them, since you can't just apply conversions against the columns in inserted.
What is blocking the client from upgrading these columns to use proper, first-class data types that haven't been deprecated since SQL Server 2005 for many good reasons (including this one)?
You'll need to re-write your trigger anyway. It currently is not multi-row safe. The trigger won't break once you have the data type corrected, it will just pick an arbitrary row from inserted and ignore the rest. So it needs to treat inserted as a set, not as a single row, since triggers in SQL Server fire per statement, not per row.

Return multiple values from a SQL Server function

How would I return multiple values (say, a number and a string) from a user-defined function in SQL Server?
Change it to a table-valued function
Please refer to the following link, for example.
Another option would be to use a procedure with output parameters - Using a Stored Procedure with Output Parameters
Here's the Query Analyzer template for an in-line function - it returns 2 values by default:
-- =============================================
-- Create inline function (IF)
-- =============================================
IF EXISTS (SELECT *
FROM sysobjects
WHERE name = N'<inline_function_name, sysname, test_function>')
DROP FUNCTION <inline_function_name, sysname, test_function>
GO
CREATE FUNCTION <inline_function_name, sysname, test_function>
(<#param1, sysname, #p1> <data_type_for_param1, , int>,
<#param2, sysname, #p2> <data_type_for_param2, , char>)
RETURNS TABLE
AS
RETURN SELECT #p1 AS c1,
#p2 AS c2
GO
-- =============================================
-- Example to execute function
-- =============================================
SELECT *
FROM <owner, , dbo>.<inline_function_name, sysname, test_function>
(<value_for_#param1, , 1>,
<value_for_#param2, , 'a'>)
GO
Erland Sommarskog has an exhaustive post about passing data in SQL Server located here:
http://www.sommarskog.se/share_data.html
He covers SQL Server 2000, 2005, and 2008, and it should probably be read in its full detail as there is ample coverage of each method's advantages and drawbacks. However, here are the highlights of the article (frozen in time as of July 2015) for the sake of providing search terms that can be used to look greater details:
This article tackles two related questions:
How can I use the result set from one stored procedure in another, also expressed as How can I use the result set from a stored
procedure in a SELECT statement?
How can I pass a table data in a parameter from one stored procedure to another?
OUTPUT Parameters
Not generally applicable, but sometimes overlooked.
Table-valued Functions
Often the best choice for output-only, but there are several restrictions.
Examples:
Inline Functions: Use this to reuse a single SELECT.
Multi-statement Functions: When you need to encapsulate more complex logic.
Using a Table
The most general solution. My favoured choice for input/output scenarios.
Examples:
Sharing a Temp Table: Mainly for a single pair of caller/callee.
Process-keyed Table: Best choice for many callers to the same callee.
Global Temp Tables: A variation of process-keyed.
Table-valued Parameters
Req. Version: SQL 2008
Mainly useful when passing data from a client.
INSERT-EXEC
Deceivingly appealing, but should be used sparingly.
Using the CLR
Req. Version: SQL 2005
Complex, but useful as a last resort when INSERT-EXEC does not work.
OPENQUERY
Tricky with many pitfalls. Discouraged.
Using XML
Req. Version: SQL 2005
A bit of a kludge, but not without advantages.
Using Cursor Variables
Not recommendable.
Example of using a stored procedure with multiple out parameters
As User Mr. Brownstone suggested you can use a stored procedure; to make it easy for all i created a minimalist example. First create a stored procedure:
Create PROCEDURE MultipleOutParameter
#Input int,
#Out1 int OUTPUT,
#Out2 int OUTPUT
AS
BEGIN
Select #Out1 = #Input + 1
Select #Out2 = #Input + 2
Select 'this returns your normal Select-Statement' as Foo
, 'amazing is it not?' as Bar
-- Return can be used to get even more (afaik only int) values
Return(#Out1+#Out2+#Input)
END
Calling the stored procedure
To execute the stored procedure a few local variables are needed to receive the value:
DECLARE #GetReturnResult int, #GetOut1 int, #GetOut2 int
EXEC #GetReturnResult = MultipleOutParameter
#Input = 1,
#Out1 = #GetOut1 OUTPUT,
#Out2 = #GetOut2 OUTPUT
To see the values content you can do the following
Select #GetReturnResult as ReturnResult, #GetOut1 as Out_1, #GetOut2 as Out_2
This will be the result: