DB2 SQLCODE -433, SQLSTATE 22001 - db2

I have created a trigger, inside the trigger I am appending lot of varchar and creating a new varchar. if I append too many varchars then I am getting below Sql Exception. (if I append 4 or 5 varchar then I am not getting this error)
I have found out that varchar maximum size is based on page size of the table space. I have checked my page size, its 8K bytes.
But The content I am appending is not 8K bytes. Please help me to resolve this error.
An error occurred in a triggered SQL statement in trigger "ORDDBA.ORD_IR_IN". Information returned for the error includes SQLCODE "-433", SQLSTATE "22001" and message tokens "ACTION|AREA_UNIT|BAL_CHG_FLAG|CANCEL_DATE|".. SQLCODE=-723, SQLSTATE=09000, DRIVER=3.66.46
declare columnNames varchar(5000);
SET columnNames='';
SET columnNames = 'value1' ;
SET columnNames = CONCAT(columnNames, '|') ;
SET columnNames = CONCAT(columnNames, 'value2') ;
SET columnNames = CONCAT(columnNames, '|') ;
SET columnNames = CONCAT(columnNames, 'value3') ;
SET columnNames = CONCAT(columnNames, '|') ;
SET columnNames = CONCAT(columnNames, 'value14') ;
SET columnNames = CONCAT(columnNames, '|') ;
SET columnNames = CONCAT(columnNames, 'value5') ;
SET columnNames = CONCAT(columnNames, '|') ;
SET columnNames = CONCAT(columnNames, 'value6') ;
SET columnNames = CONCAT(columnNames, '|') ;
SET columnNames = CONCAT(columnNames, 'value6') ;
SET columnNames = CONCAT(columnNames, '|') ;
SET columnNames = CONCAT(columnNames, 'value8') ;
SET columnNames = CONCAT(columnNames, '|') ;
SET columnNames = CONCAT(columnNames, 'value9') ;
SET columnNames = CONCAT(columnNames, '|') ;
SET columnNames = CONCAT(columnNames, 'value10') ;
SET columnNames = CONCAT(columnNames, '|') ;
SET columnNames = CONCAT(columnNames, 'value11') ;
SET columnNames = CONCAT(columnNames, '|') ;
SET columnNames = CONCAT(columnNames, 'value12') ;
SET columnNames = CONCAT(columnNames, '|') ;
SET columnNames = CONCAT(columnNames, 'value13') ;
SET columnNames = CONCAT(columnNames, '|') ;
SET columnNames = CONCAT(columnNames, 'value14') ;
SET columnNames = CONCAT(columnNames, '|') ;
SET columnNames = CONCAT(columnNames, 'value15') ;
SET columnNames = CONCAT(columnNames, '|') ;
SET columnNames = CONCAT(columnNames, 'value16') ;

From your comment:
if I count the number of character in the varchar its less than 5000, seems DB2 counting in different way so its failing. Then I changed the datatype to CLOB, then its working fine
This is because the length of a varchar is given in bytes, while the length of a clob is given in characters (documentation).
Based on character encoding, a single character may be longer than one byte. Therefore it is not always possible to store 5000 characters in a varchar(5000).

Varchar columns defined in Octets are a match to characters. Codeunits32 are where I have fallen into this trap.

Related

TSQL relace a string text with variable

I am trying to replace the folder location in line three of the code below (Set #ProjectBinary ) to a variable.
The original code:
DECLARE #ProjectBinary as varbinary(max)
DECLARE #operation_id as bigint
Set #ProjectBinary = (SELECT * FROM OPENROWSET(BULK 'C:\MyProjects\ SSISPackage_ProjectDeployment.ispac', SINGLE_BLOB) as BinaryData)
Exec catalog.deploy_project #folder_name = 'SSIS Packages', #project_name = 'DeployViaStoredProc_SSIS', #Project_Stream = #ProjectBinary, #operation_id = #operation_id out
I have created a variable:
DECLARE #Location AS varchar(250) = 'C:\SSIS\DWH_IS.ispac'
DECLARE #ProjectBinary as varbinary(max)
DECLARE #operation_id as bigint
Set #ProjectBinary = ('SELECT * FROM OPENROWSET(BULK ' + #Location + ', SINGLE_BLOB') as BinaryData)
Exec catalog.deploy_project #folder_name = 'SSIS Packages', #project_name = 'DeployViaStoredProc_SSIS', #Project_Stream = #ProjectBinary, #operation_id = #operation_id out
I keep getting an error:
Msg 257, Level 16, State 3, Line 61
Implicit conversion from data type varchar to varbinary(max) is not allowed. Use the CONVERT function to run this query.
Any suggestions on how to change this to get the code running please?
You need to break it down as follows
DECLARE #SQL nvarchar(1000), #ProjectBinary as varbinary(max);
SET #SQL = N'SELECT #Blob = (SELECT * FROM OPENROWSET(BULK ''' + #Location + ''', SINGLE_BLOB) as BinaryData)'
EXEC sp_executesql #SQL, N'#Blob varbinary(max) OUTPUT', #ProjectBinary OUTPUT;
The line Set #ProjectBinary = (.. can't dynamic or parametrised

Random Number Generator - Create a matrix of random numbers where the values in each row sum to X in T-SQL?

How to generate a matrix of random numbers where the values in each row add up to X in T-SQL?
The solution matrix should be dynamic:
User can specify number of columns to be returned in the result
User can specify number of rows to be returned in the result
Each row must sum to X (eg. 1)
create proc RandomNumberGenerator
(
#rows int
, #cols int
, #rowsumtotal float
)
as
....
First create a UDF...
CREATE FUNCTION [dbo].[_ex_fn_SplitToTable] (#str varchar(5000), #sep varchar(1) = null)
RETURNS #ReturnVal table (n int, s varchar(5000))
AS
/*
Alpha Test
-----------
select * from [dbo].[_ex_fn_SplitToTable_t2]('a b c d e',' ')
*/
BEGIN
if #sep = ' '
begin
set #sep = CHAR(167)
set #str = REPLACE(#str,' ',CHAR(167))
end
declare #str2 varchar(5000)
declare #sep2 varchar(1)
if LEN(ISNULL(#sep,'')) = 0
begin
declare #i int
set #i = 0
set #str2 = ''
declare #char varchar(1)
startloop:
set #i += 1
--print #i
set #char = substring(#str,#i,1)
set #str2 = #str2 + #char + ','
if LEN(#str) <= #i
goto exitloop
goto startloop
exitloop:
set #str2 = left(#str2,LEN(#str2) - 1)
set #sep2 = ','
--print #str2
end
else
begin
set #str2 = #str
set #sep2 = #sep
end
;WITH Pieces(n, start, stop) AS (
SELECT 1, 1, CHARINDEX(#sep2, #str2)
UNION ALL
SELECT n + 1, stop + 1, CHARINDEX(#sep2, #str2, stop + 1)
FROM Pieces
WHERE stop > 0
)
insert into #ReturnVal(n,s)
SELECT n,
SUBSTRING(#str2, start, CASE WHEN stop > 0 THEN stop-start ELSE 5000 END) AS s
FROM Pieces option (maxrecursion 32767)
RETURN
END
GO
Then, create this stored proc...
CREATE PROC [dbo].[RandomNumberGenerator]
(
#Pockets int = 6,
#SumTo float = 100,
#i_iterations int = 100
)
/*
ALPHA TEST
----------
exec RandomNumberGenerator 10, 100, 500
*/
AS
if object_id('tempdb..#_Random_00') is not null drop table #_Random_00
declare #columnstring varchar(max) = (SELECT REPLICATE('c ',#Pockets) as Underline)
print #columnstring
if object_id('tempdb..#_Random_columns') is not null drop table #_Random_columns
select s+CONVERT(varchar,dbo.PadLeft(convert(varchar,n),'0',3)) cols
into #_Random_columns
from [dbo].[_ex_fn_SplitToTable](#columnstring,' ') where LEN(s) > 0
-- ===========================
--select * from #_Random_columns
-- ===========================
declare #columns_sql varchar(max)
set #columns_sql =
(
select distinct
stuff((SELECT distinct + cast(cols as varchar(50)) + ' float, '
FROM (
select cols
from #_Random_columns
) t2
--where t2.n = t1.n
FOR XML PATH('')),3,0,'')
from (
select cols
from #_Random_columns
) t1
)
set #columns_sql = LEFT(#columns_sql,LEN(#columns_sql) - 1)
print #columns_sql
declare #sql varchar(max)
set #sql = 'if object_id(''tempdb..##_proctable_Random_01'') is not null drop table ##_proctable_Random_01 '
print #sql
execute(#sql)
set #sql = 'create table ##_proctable_Random_01 (rowid int,' + #columns_sql + ')'
print #sql
execute(#sql)
declare #TotalOfRand float
declare #i_inner int
declare #i_outer int
set #i_outer = 0
start_outer:
set #i_outer = #i_outer + 1
set #i_inner = 0
declare #sumstring varchar(max)
set #sumstring = ''
start_inner:
set #i_inner = #i_inner+1
set #sumstring = #sumstring + CONVERT(varchar, rand()) + ','
if #i_inner >= #Pockets
goto exit_inner
goto start_inner
exit_inner:
set #TotalOfRand = ( select sum(convert(float,s)) from dbo._ex_fn_SplitToTable(#sumstring,',') )
declare #sumstring_quotient varchar(max)
set #sumstring_quotient = replace(#sumstring,',', '/' + Convert(varchar,#TotalOfRand) + '*' + convert(varchar,#SumTo) + ',')
set #sumstring_quotient = LEFT(#sumstring_quotient,len(#sumstring_quotient) - 1)
print #sumstring_quotient
set #sql = '
insert into ##_proctable_Random_01
select
( select count(*) + 1 from ##_proctable_Random_01 ) rowid,' + #sumstring_quotient
execute(#sql)
if #i_outer >= #i_iterations
goto exit_outer
goto start_outer
exit_outer:
select * from ##_proctable_Random_01
drop table ##_proctable_Random_01
GO

T-SQL Syntax - word parser

I have a word list in a variable. The words are comma delimited. I am trying to save them to individual record in a database. I found another question which does this and works, but it saves every word. I tried to modify it so that I only save unique words, and count duplicate as I go. I think the logic below is correct, but my syntax is not working.
if #FoundWord = 0 SET #WordsUsed = #WordsUsed + '' + #Word + ''
** is not concatenating the next word onto the end of the #WordsUsed variable
if #FoundWord = 0 INSERT INTO mydata.dbo.words (ProjectNumber, WordCount, Word) VALUES( '5', '1', #Word )
** doesn't seem to be doing anything at all ... I'm getting no records written to the words table
The entire code follows:
declare #SplitOn nvarchar(5) = ','
BEGIN
DECLARE #split_on_len INT = LEN(#SplitOn)
DECLARE #start_at INT = 1
DECLARE #end_at INT
DECLARE #data_len INT
DECLARE #WordsUsed varchar(max)
DECLARE #FoundWord int
DECLARE #Word varchar(100)
Set #WordsUsed = '**'
WHILE 1=1
BEGIN
SET #end_at = CHARINDEX(#SplitOn,#txt1,#start_at)
SET #data_len = CASE #end_at WHEN 0 THEN LEN(#txt1) ELSE #end_at-#start_at END
set #Word = SUBSTRING(#txt1,#start_at,#data_len)
SET #FoundWord = CHARINDEX('*' & #Word & '*', #WordsUsed)
if #FoundWord = 0 SET #WordsUsed = #WordsUsed & '*' & #Word & '*'
if #FoundWord = 0 INSERT INTO mydata.dbo.words (ProjectNumber, WordCount, Word) VALUES( '5', '1', #Word )
if #FoundWord > 0 Update mydata.dbo.words set WordCount = WordCount + 1 where projectnumber = 5 and word = #word
IF #end_at = 0 BREAK
SET #start_at = #end_at + #split_on_len
END
RETURN
END;
Here's a function you can try. It splits an unlimited-sized string based on the delimiter of your choice. The output of the function is a table - so you can then select distinct from that to store your word list. You'd call it something like:
insert YourWordlistTable ( Word ) --> just making up table/column names here
select distinct Data
from dbo.StringSplit( #yourVar, ',' )
Here's the definition of the function:
create function dbo.StringSplit
(
#string nvarchar( max ),
#delimiter nvarchar( 255 )
)
returns #t table ( Id int, Data nvarchar( 4000 ) )
as begin
with Split( startPosition, endPosition )
as
(
select
cast( 0 as bigint ) as startPosition,
charindex( #delimiter, #string ) as endPosition
union all
select
endPosition + 1, charindex( #delimiter, #string, endPosition + 1 )
from
Split
where
endPosition > 0
)
insert #t
select
row_number() over ( order by ( select 1 ) ) as Id,
substring( #string, startPosition, coalesce( nullif( endPosition, 0 ), len( #string ) + 1 ) - startPosition ) collate Latin1_General_CS_AS as Data
from
Split
option( maxrecursion 0 );
return;
end
I originally posted, then deleted, then reposted this when I realized I'd given an inline function I use that never got called on strings longer than 100 words. I've since modified it to support indefinite recursion - although it can't be an inline function this way.
Inline functions are generally faster because SQL can incorporate the inline function's statement into the query plan of the statements that call the function. However, that does not appear to be an option available in an inline function.
why can't you use
select count(distinct value) from dbo.split(',',#txt1) where #txt1 is he string will give you distinct count of words
If you are looking for word wise count
select value,count(1) from dbo.split(',',#txt1) group by value
shoud do this

Getting string from variable

DECLARE #dbfilepath nvarchar(128)
SET #dbfilepath = 'C:\SqlDataFiles\Cache.mdf'
GO
USE [master]
GO
CREATE DATABASE [Cache] ON PRIMARY
( NAME = N'Cache', FILENAME = #dbfilepath, SIZE = 3072KB , MAXSIZE = UNLIMITED, FILEGROWTH = 1024KB )
GO
Why doesn't this work?
It gives:
Msg 102, Level 15, State 1, Line 3
Incorrect syntax near '#dbfilepath'.
You need to exec it;
USE [master]
GO
DECLARE #dbfilepath nvarchar(128) = 'C:\MSSQL\Cache.mdf'
DECLARE #SQL NVARCHAR(MAX) = N'CREATE DATABASE [Cache] ON PRIMARY (NAME = N''Cache'', FILENAME = ''' + #dbfilepath + ''', SIZE = 3072KB , MAXSIZE = UNLIMITED, FILEGROWTH = 1024KB )'
EXEC(#SQL)
Try this:
DECLARE #dbfilepath nvarchar(128);
SET #dbfilepath = 'C:\\SqlDataFiles\\Cache.mdf';
PRINT #dbfilepath;
To use #dbfilepath in the Create Database statement, dynamic sql needs to be used.

T-SQL function for generating slugs?

Quick check to see if anyone has or knows of a T-SQL function capable of generating slugs from a given nvarchar input. i.e;
"Hello World" > "hello-world"
"This is a test" > "this-is-a-test"
I have a C# function that I normally use for these purposes, but in this case I have a large amount of data to parse and turn into slugs, so it makes more sense to do it on the SQL Server rather than have to transfer data over the wire.
As an aside, I don't have Remote Desktop access to the box so I can't run code (.net, Powershell etc) against it
Thanks in advance.
EDIT:
As per request, here's the function I generally use to generate slugs:
public static string GenerateSlug(string n, int maxLength)
{
string s = n.ToLower();
s = Regex.Replace(s, #"[^a-z0-9s-]", "");
s = Regex.Replace(s, #"[s-]+", " ").Trim();
s = s.Substring(0, s.Length <= maxLength ? s.Length : maxLength).Trim();
s = Regex.Replace(s, #"s", "-");
return s;
}
You can use LOWER and REPLACE to do this:
SELECT REPLACE(LOWER(origString), ' ', '-')
FROM myTable
For wholesale update of the column (the code sets the slug column according to the value of the origString column:
UPDATE myTable
SET slug = REPLACE(LOWER(origString), ' ', '-')
This is what I've come up with as a solution. Feel free to fix / modify where needed.
I should mention that the database I'm currently developing against is case insensitive hence the LOWER(#str).
CREATE FUNCTION [dbo].[UDF_GenerateSlug]
(
#str VARCHAR(100)
)
RETURNS VARCHAR(100)
AS
BEGIN
DECLARE #IncorrectCharLoc SMALLINT
SET #str = LOWER(#str)
SET #IncorrectCharLoc = PATINDEX('%[^0-9a-z ]%',#str)
WHILE #IncorrectCharLoc > 0
BEGIN
SET #str = STUFF(#str,#incorrectCharLoc,1,'')
SET #IncorrectCharLoc = PATINDEX('%[^0-9a-z ]%',#str)
END
SET #str = REPLACE(#str,' ','-')
RETURN #str
END
Mention to: http://blog.sqlauthority.com/2007/05/13/sql-server-udf-function-to-parse-alphanumeric-characters-from-string/ for the original code.
I know this is an old thread, but for future generation, I found one function that deals even with accents here:
CREATE function [dbo].[slugify](#string varchar(4000))
RETURNS varchar(4000) AS BEGIN
declare #out varchar(4000)
--convert to ASCII
set #out = lower(#string COLLATE SQL_Latin1_General_CP1251_CS_AS)
declare #pi int
--I'm sorry T-SQL have no regex. Thanks for patindex, MS .. :-)
set #pi = patindex('%[^a-z0-9 -]%',#out)
while #pi>0 begin
set #out = replace(#out, substring(#out,#pi,1), '')
--set #out = left(#out,#pi-1) + substring(#out,#pi+1,8000)
set #pi = patindex('%[^a-z0-9 -]%',#out)
end
set #out = ltrim(rtrim(#out))
-- replace space to hyphen
set #out = replace(#out, ' ', '-')
-- remove double hyphen
while CHARINDEX('--', #out) > 0 set #out = replace(#out, '--', '-')
return (#out)
END
Here's a variation of Jeremy's response. This might not technically be slugifying since I'm doing a couple of custom things like replacing "." with "-dot-", and stripping out apostrophes. Main improvement is this one also strips out all consecutive spaces, and doesn't strip out preexisting dashes.
create function dbo.Slugify(#str nvarchar(max)) returns nvarchar(max)
as
begin
declare #IncorrectCharLoc int
set #str = replace(replace(lower(#str),'.',' dot '),'''','')
-- remove non alphanumerics:
set #IncorrectCharLoc = patindex('%[^0-9a-z -]%',#str)
while #IncorrectCharLoc > 0
begin
set #str = stuff(#str,#incorrectCharLoc,1,' ')
set #IncorrectCharLoc = patindex('%[^0-9a-z -]%',#str)
end
-- remove consecutive spaces:
while charindex(' ',#str) > 0
begin
set #str = replace(#str, ' ', ' ')
end
set #str = replace(#str,' ','-')
return #str
end
I took Jeremy's response a couple steps further by removing all consecutive dashes even after spaces are replaced, and removed leading and trailing dashes.
create function dbo.Slugify(#str nvarchar(max)) returns nvarchar(max) as
begin
declare #IncorrectCharLoc int
set #str = replace(replace(lower(#str),'.','-'),'''','')
-- remove non alphanumerics:
set #IncorrectCharLoc = patindex('%[^0-9a-z -]%',#str)
while #IncorrectCharLoc > 0
begin
set #str = stuff(#str,#incorrectCharLoc,1,' ')
set #IncorrectCharLoc = patindex('%[^0-9a-z -]%',#str)
end
-- replace all spaces with dashes
set #str = replace(#str,' ','-')
-- remove consecutive dashes:
while charindex('--',#str) > 0
begin
set #str = replace(#str, '--', '-')
end
-- remove leading dashes
while charindex('-', #str) = 1
begin
set #str = RIGHT(#str, len(#str) - 1)
end
-- remove trailing dashes
while len(#str) > 0 AND substring(#str, len(#str), 1) = '-'
begin
set #str = LEFT(#str, len(#str) - 1)
end
return #str
end
-- Converts a title such as "This is a Test" to an all lower case string such
-- as "this-is-a-test" for use as the slug in a URL. All runs of separators
-- (whitespace, underscore, or hyphen) are converted to a single hyphen.
-- This is implemented as a state machine having the following four states:
--
-- 0 - initial state
-- 1 - in a sequence consisting of valid characters (a-z, A-Z, or 0-9)
-- 2 - in a sequence of separators (whitespace, underscore, or hyphen)
-- 3 - encountered a character that is neither valid nor a separator
--
-- Once the next state has been determined, the return value string is
-- built based on the transitions from the current state to the next state.
--
-- State 0 skips any initial whitespace. State 1 includes all valid slug
-- characters. State 2 converts multiple separators into a single hyphen
-- and skips trailing whitespace. State 3 skips any punctuation between
-- between characters and, if no additional whitespace is encountered,
-- then the punctuation is not treated as a word separator.
--
CREATE FUNCTION ToSlug(#title AS NVARCHAR(MAX))
RETURNS VARCHAR(MAX)
AS
BEGIN
DECLARE #retval AS VARCHAR(MAX) = ''; -- return value
DECLARE #i AS INT = 1; -- title index
DECLARE #c AS CHAR(1); -- current character
DECLARE #state AS INT = 0; -- current state
DECLARE #nextState AS INT; -- next state
DECLARE #tab AS CHAR(1) = CHAR(9); -- tab
DECLARE #lf AS CHAR(1) = CHAR(10); -- line feed
DECLARE #cr AS CHAR(1) = CHAR(13); -- carriage return
DECLARE #separators AS CHAR(8) = '[' + #tab + #lf + #cr + ' _-]';
DECLARE #validchars AS CHAR(11) = '[a-zA-Z0-9]';
WHILE (#i <= LEN(#title))
BEGIN
SELECT #c = SUBSTRING(#title, #i, 1),
#nextState = CASE
WHEN #c LIKE #validchars THEN 1
WHEN #state = 0 THEN 0
WHEN #state = 1 THEN CASE
WHEN #c LIKE #separators THEN 2
ELSE 3 -- unknown character
END
WHEN #state = 2 THEN 2
WHEN #state = 3 THEN CASE
WHEN #c LIKE #separators THEN 2
ELSE 3 -- stay in state 3
END
END,
#retval = #retval + CASE
WHEN #nextState != 1 THEN ''
WHEN #state = 0 THEN LOWER(#c)
WHEN #state = 1 THEN LOWER(#c)
WHEN #state = 2 THEN '-' + LOWER(#c)
WHEN #state = 3 THEN LOWER(#c)
END,
#state = #nextState,
#i = #i + 1
END
RETURN #retval;
END
To slug with Vietnamese unicode
CREATE function [dbo].[toslug](#string nvarchar(4000))
RETURNS varchar(4000) AS BEGIN
declare #out nvarchar(4000)
declare #from nvarchar(255)
declare #to varchar(255)
--convert to ASCII dbo.slugify
set #string = lower(#string)
set #out = #string
set #from = N'ýỳỷỹỵáàảãạâấầẩẫậăắằẳẵặéèẻẽẹêếềểễệúùủũụưứừửữựíìỉĩịóòỏõọơớờởỡợôốồổỗộđ·/_,:;'
set #to = 'yyyyyaaaaaaaaaaaaaaaaaeeeeeeeeeeeuuuuuuuuuuuiiiiioooooooooooooooood------'
declare #pi int
set #pi = 1
--I'm sorry T-SQL have no regex. Thanks for patindex, MS .. :-)
while #pi<=len(#from) begin
set #out = replace(#out, substring(#from,#pi,1), substring(#to,#pi,1))
set #pi = #pi + 1
end
set #out = ltrim(rtrim(#out))
-- replace space to hyphen
set #out = replace(#out, ' ', '-')
-- remove double hyphen
while CHARINDEX('--', #out) > 0 set #out = replace(#out, '--', '-')
return (#out)
END