Subtle differences in Teradata and SQL Server

Imagine the hair pulling experience, when you port knowledge from one RDBMS to another, and it just doesn’t work. I had one such experience today, when I had to generate a certain filter for at Query. I wanted to combine the year and month value, to filter on the unique month key which consisted of the concatenation of year and month (YYYYMM).

In SQL Server, you could do something like this:

SELECT
    CAST
(DATEPART(YEAR,GETDATE()) AS VARCHAR(4))+
    IIF(DATEPART(MONTH,GETDATE())< 10
    ,‘0’+CAST(DATEPART(MONTH,GETDATE())AS VARCHAR(2))
,
CAST(DATEPART(MONTH,GETDATE())AS VARCHAR(2))
)

The result of the above query, would be ‘201402’. But, in Teradata, that just results in 2016 (for the current month of February), even when doing the explicit cast mind you.

Turns out, that CONCAT(…) is your friend – Otherwise you just end up with a number, even when explicitly casting to VARCHAR(x)

SELECT
CONCAT(
CAST( EXTRACT( YEARFROMCURRENT_DATE ) AS VARCHAR(4) ),
CASE
WHEN EXTRACT( MONTHFROMCURRENT_DATE ) < 10THEN
CONCAT( '0' , CAST( EXTRACT( MONTHFROMCURRENT_DATE ) AS VARCHAR(2) ) )
ELSE
CAST( EXTRACT( MONTHFROMCURRENT_DATE ) AS VARCHAR(2) )
END
)

 

Loading

How to do a String REPLACE in Teradata

String Replace does not exist but can be accomplished with the following procedure:

INSTALL REQUIREMENTS:–

1) GRANT ALL ON “%TDUser%” TO “%TDUser%” WITH GRANT OPTION

2) C++ compiler, if running the TD Demo

How to replace “old” with “new” so that  ‘Hello, old world’ becomes ‘Hello, new world’

1) Logon to teradata using the %TDUser% login—

2) Create custom procedure

REPLACE PROCEDURE SysDBA.StringReplace ( IN TargetString VARCHAR(30000) — 33998 , IN SearchString VARCHAR(255) , IN ReplaceString VARCHAR(255) , OUT OutString VARCHAR(30000) )

BEGIN DECLARE sOutString VARCHAR(30000);
DECLARE sTmpSearchStr VARCHAR(30000);
DECLARE iTargetStrLen INTEGER;
DECLARE iSearchStrLen INTEGER;
DECLARE iSearchIndex INTEGER;

SET sOutString = ”;
SET iTargetStrLen = CHAR_LENGTH( TargetString );
SET iSearchStrLen = CHAR_LENGTH( SearchString );

IF (iSearchStrLen <= 0) THEN SET OutString = TargetString;
ELSEIF (iTargetStrLen <= 0) THEN SET OutString = ”;
ELSEIF (iSearchStrLen > iTargetStrLen) THEN SET OutString = TargetString;
ELSE SET sOutString = ”;

SET sTmpSearchStr = TargetString;
SET iSearchIndex = POSITION( SearchString IN sTmpSearchStr );

WHILE iSearchIndex <> 0 DO SET sOutString = sOutString || SUBSTR( sTmpSearchStr , 1 , iSearchIndex – 1 ) || ReplaceString ;

SET sTmpSearchStr = SUBSTR( sTmpSearchStr , iSearchIndex + iSearchStrLen , CHAR_LENGTH(sTmpSearchStr) – (iSearchIndex + iSearchStrLen) + 1 );
SET iSearchIndex = POSITION( SearchString IN sTmpSearchStr );

END WHILE;

SET sOutString = sOutString || SUBSTR ( sTmpSearchStr , 1 , CHAR_LENGTH(TRIM(TRAILING FROM sTmpSearchStr)) ); SET OutString = sOutString; END IF;
END;

3) Note, this can only run in another procedure, so write another procedure that calls the replace procedure. DECLARE outStr VARCHAR(33998);– CALL testload.Replace(colum1, ‘old ‘, ”, OutString)—- and get the output in the OutString variable

Loading

Restored database konflikter med et opdaterings deploy fra VS DB Ed.

Jeg løb ind i et lidt filøjerligt issue her til aftens da jeg skulle lave et opdateringsdeploy fra VS ud til min dev instans af en database.
Jeg havde modtaget en backup fra en kollega, der indeholdt en masse testdata, som jeg restorede ind og overskrev den eksisterende instans jeg havde på min maskine.
Efterfølgende fik jeg kørt en del af de tests jeg skulle, men undervejs kom der opdateringer til skemaet. Da jeg så ville opdatere min instans modtog jeg følgende besked fra VS:

The database owner SID recorded in the master database differs from the database owner SID recorded in database…

For at gøre en lang historie kort googlede jeg en løsning, og for at jeg ikke selv skal glemme den så let, poster jeg den her:
use mydb
go
EXEC dbo.sp_changedbowner @loginame = N’sa’, @map = false

Loading

Kør SQL statement mod alle databaser

Der findes en udokumenteret system stored procedure fra Microsoft, der gør det muligt at eksekvere en T-SQL sætning mod alle databaser. Uden at skulle sætte en cursor op mod sysdatabases tabellen.

Syntax:
EXEC sp_MSforeachdb @command
(hvor @command er en streng af variabel længde)

Eksempel:
Dette eksempel returnerer en liste med alle tabeller i alle datasbase på en given SQL-Server instans
DECLARE @command varchar(1000)
SELECT @command = ‘USE ? SELECT name FROM sysobjects WHERE xtype = ”U” ORDER BY name’
EXEC sp_MSforeachdb @command

Se i øvrigt:
http://www.mssqltips.com/tip.asp?tip=1414

Loading

” == 0

Opdagede i dag en meget underlig måde at programmere på. Under en portering fra SQL Server 2000 til SQL Server 2005 stødte jeg på en fejlbesked i en stored procedure. Fejlbeskeden lød meget mærkelig og det viste sig også at det ikke var den helt rigtige besked der blev vist. Af meget uforklarlige årsager havde 3. parts udviklere forkærlighed for at benytte sig af notationen som følger:

SELECT CAST( '' AS INT(4) ) AS Test

Det går godt i SQL Server 2000, og der returneres et 0. Det gør det bare ikke i SQL Server 2005, her knækker den nakken på udtrykket.

Det jeg ikke lige begriber er, hvordan man kommer konstruktionen, at en tom streng selvfølgelig kan cast’es til 0 (nul). Det giver da ingen mening?

Loading