Is rand() predictable in SQL Server - tsql

Recently I was told that numbers generated using rand() in SQL Server 2008 returns predictable number sequence. Is it true?
declare #RandNum int
set #RandNum=RAND()*100
print #RandNum

Related

Convert differences between SQL Server 2008 R2 and 2012

I've got an issue while executing a SQL statement in SQL Server 2012 while it's perfectly working in a SQL Server 2008 R2...
The error message is :
Msg 8114, Level 16, State 5, Line 1
Error converting data type varchar
to numeric.
I want to execute this SQL Select statement :
Select
count(*)
from IMPORTBM
inner join ATTRIBUTE on ATT_ATTRIBUTE_ID = IMP_ATTRIBUTE_ID
where IMP_LOCATION_ID = 2
AND IMP_SERIAL_ID = 310001
AND IMP_VERSION_ID = 1
AND (
(ATT_ATTRIBUTE = 'PS_APISizing'
AND IMP_VALUE = 'C')
OR
(ATT_ATTRIBUTE = 'DTD'
AND ISNUMERIC(IMP_VALUE) = 1
AND CAST( IMP_VALUE as NUMERIC(38,19)) <= 0.469)
OR
(ATT_ATTRIBUTE = 'IOD'
AND ISNUMERIC(IMP_VALUE) = 1
AND CAST( IMP_VALUE as NUMERIC(38,19)) BETWEEN 3.684 AND 4.225)
)
Could you help me finding out why it's not working with SQL Server 2012 please ?
The problem is that conditions are not always evaluated in the order you place them. This means that Cast(IMP_VALUE as numeric(38, 19)) can fail when it is a non-numeric value, if the query execution plan happens to evaluate this before the IsNumeric(IMP_VALUE) = 1.
This is not determined by how many clauses there are or what version of SQL Server you're running--those are only coincidences. The problem is exactly as I described. The fact that you get different results with different queries is due to different queries, or different servers, using different execution plans.
The cure is to make sure that all conditions will not throw an error, no matter what order they are executed in.
For all versions of SQL Server, you can do this:
Convert(
numeric(38,19),
CASE WHEN IsNumeric(IMP_VALUE) = 1 THEN IMP_VALUE ELSE NULL END
) <= 0.469
Or, in SQL Server 2012 and up, you can use Try_Convert:
Try_Convert(numeric(38,19), IMP_VALUE) <= 0.469
If your server complains that this is not a built-in function name, then it is likely that your database was upgraded from a prior version and you need to alter the database compatibility level. Note that doing this could have some other effects in the system that you need to consider, so study up on it first, and try it out in a non-production system before doing it in production (or do it during a non-critical period and set the compatibility level back if you run into any issues). The danger is not that any damage will occur, but that query results could be different or errors could occur (different ordering of query or stored procedure results being a more common occurrence).
ALTER DATABASE database_name
SET COMPATIBILITY_LEVEL = 110; -- SQL Server 2012
What is the definition of the table? (IMP_VALUE at least). Why not store numeric in the 1st place...
2008 and 2012 query plan probably differ and does not handle the parameter and condition in the same order.
With SQL Server 2012 (compatibility level 110) you can try to replace the 2 cast:
AND ISNUMERIC(IMP_VALUE) = 1
AND CAST( IMP_VALUE as NUMERIC(38,19)) <= 0.469)
by
AND TRY_CONVERT(NUMERIC(38,19), IMP_VALUE) <= 0.469
AND TRY_CONVERT(NUMERIC(38,19), IMP_VALUE) BETWEEN 3.684 AND 4.225
It returns NULL without error when it cannot convert it.

while loop in sybase ASE

I am using the below sybase version of
Adaptive Server Enterprise/15.0.3/EBF 16375/P/NT (IX86)/Windows 2003/ase1503/2670/32-bit/OPT/Mon Nov 17 17:49:12 2008
Trying to work upon a simple while loop, however it runs only once. Using interactive sql GUI to run it.
declare #i int, #j int
set #i=1
set #j=5
while(#i<=#j)
begin
select '1'
set #i=#i+1
end

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.

SSRS 2005 passing parameters to SQL Server 2000 stored procedure

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)

How about the performance between PATINDEX and CHARINDEX?

At all times I use CHARINDEX in stored procedure to check NVARCHAR(MAX) type of variable, but today I find that the CHARINDEX has an 8,000 byte limit!
I find this article SQL CHARINDEX() Has Data Size Limitations.
So I replace CHARINDEX with PATINDEX, but I do not know the performance between PATINDEX and CHARINDEX.
CHARINDEX has limit of 8000 for the string you are looking for. Not for the string you are searching.
That article is probably wrong unless you want to look for strings > 8000/4000 length. However, it also uses text datatype which is deprecated. It's dated 2007, so it would be SQL Server 2005 or 2000 he used but SQL Server 2005 BOL does not mention 8000 at all and it's not something I've tried.
From the SQL Server 2008 BOL:
CHARINDEX ( expression1 ,expression2 [
, start_location ] )
expression1 Is a character expression that
contains the sequence to be found.
expression1 is limited to 8000
characters.
expression2 Is a character expression to be searched.
Note: PATINDEX does not mention 8000 limit for SQL 2008 or 2005.
Finally, I'd use CHARINDEX because I think it's more intuitive for straightforward searches if you don't need pattern matching and it supports long strings
CHARIndex does have 8000-byte (not character) limit for the string you are searching, IF the datatype is text or ntext. If the datatype is varchar(max) or nvarchar(max), the 8000-byte limit is not in effect; it searches the entire string. (I was just bit by this.) I resolved this just using CAST: CHARINDEX(searchterm, CAST(columnname as nvarchar(max))