SQL Server: how to remove leading 'A's from base64 string - sql-server

I'm working on SQL Server and trying to create a single key combining data from bigint and string columns. To minimize the size of bigint's represented as strings I'm using Base 64 encoding. The problem is that the result includes leading 'A's meaning base64 zeroes and it increases the size of the resulting field. What is the way to remove these leading A using T-SQL or XQuery?
Sample code:
DECLARE #binInput VARBINARY(MAX)
SET #binInput = CAST(123 AS VARBINARY(MAX))
SELECT CAST(N'' AS XML).value('xs:base64Binary(sql:variable("#binInput"))', 'varchar(max)')
I have a resulting AAAAew== where I would prefer to see just ew because of the idea is to make the final string as short as it possible and base64 string should be shorter than base10.
update 1: as were suggested by Richard Boyce I tried to convert bigint to the equal string, but it gives null as a result of base64 conversion
declare #input bigint
declare #varInput nvarchar(max)
set #input = 123
set #varInput = cast(cast(#input as varbinary(max)) as varchar(max))
select CAST(N'' AS xml).value('xs:base64Binary(sql:variable("#varInput"))', 'varchar(max)')
update 2: the current solution is to get a base64binary string and to remove leading 'A's and trailing '='s. It's not perfect, so any suggestions are welcome. Actual code:
declare #input bigint
set #input = 1234567890
declare #output varchar(max)
set #output = (select cast(#input as varbinary(max)) for xml path(''),binary base64)
set #output = replace(ltrim(replace(#output,'A',' ')),' ','A') -- remove leading 'A's
set #output = replace(#output,'=','') -- remove trailing '='s
select #output

Rather than trying to remove leading "A's" from the encoded result look at preventing them in the first place.
You need to convert your number to a string before encoding.
Try this
DECLARE #binInput VARBINARY(MAX)
SET #binInput = CAST(CAST(123 AS VARCHAR(MAX)) AS VARBINARY(MAX))
DECLARE #Result VARCHAR(MAX)
SELECT #Result = CAST(N'' AS XML).value('xs:base64Binary(sql:variable("#binInput"))', 'varchar(max)')
SELECT CAST(CAST(N'' AS XML).value('xs:base64Binary(sql:variable("#Result"))', 'varbinary(max)') AS VARCHAR(MAX))
Note that when encoded "123" becomes "MTIz" not ew==

Not wanting to leave an answer that doesn't answer the question, here's how to remove a number of leading A's from a string (but the answer #Richard gave is better):
DECLARE #VAL NVARCHAR(MAX) = N'AAAA12345ABCD9876=='
SELECT SUBSTRING(#VAL,PATINDEX('%[^A]%',#VAL), LEN(#VAL))
----------------
12345ABCD9876==

Related

Remove a value from a comma separated string in sql stored procedure

I have a field that store the comma separated id's of publications. Such as 123456,2345678,123567,2345890 etc. When I pull the data from the database I put it into a json object and the web page loops the values and displays the data. Works great.
What I would like to do is to send the stored proc one of the numbers and the stored proc will remove it from the string and save it back to the table. Such as the end user worked on publication 123567 and now wants to make it completed, so I want to remove it from the string so they don't see it in the future. I have a split function in the database but I don't know how to wire it up to delete or rebuild the string without the publication ID.
I don't have any code to show because I am at a loss to start. I figure I need to pass the entire string and the ID. Split the string and loop each value to rebuild a new string but check if the ID is there and skip it.
Is this the best way to do this?
Thanks for your help
what I've ended up with as the base to work from is:
ALTER FUNCTION dbo.RemovePMID (
#S VARCHAR(MAX)
,#PMID VARCHAR(15)
)
RETURNS VARCHAR(MAX)
AS
BEGIN
DECLARE #T VARCHAR(50)
DECLARE #W VARCHAR(50)
SET #T = ''
WHILE len(#S) > 0
BEGIN
SET #W = left(#S, charindex(',', #S + ',') - 1)
IF charindex(#W, + #PMID) = 0
SET #T = #T + ',' + #W
SET #S = stuff(#S, 1, charindex(',', #S + ','), '')
END
RETURN substring(#T, 2, len(#T) - 2)
END
GO
No need for loops (please take a peek at Larnu's suggestion for your parse/split function)
That said, consider the following
Example
Declare #S varchar(max) = '123456,2345678,123567,2345890'
Declare #Zap varchar(50)='123456'
Select reverse(stuff(reverse(stuff(replace(','+#S+',',','+#Zap+',',','),1,1,'')),1,1,''))
Returns
2345678,123567,2345890

Not able to replace special character in nvarchar string

I am trying to split a string which is nvarchar(max)
if I pass the string like
#String_xyz = 'abc#def#ghi$jkl'
Then I am able to replace the special character but my character comes in a unreadable format like ?????
If I send my string like this way
#String_xyz = N'abc#def#ghi$jkl'
Then I am not able to replace any special character
Let say
DECLARE #string nvarchar(max)
SET #string = 'என்$பெயர்#PIN#ஆகிறது##என்$பெயர்#KUL#ஆகிறது'
SET #string = replace(#string,'##',' ') -- This work perfect
if
DECLARE #string nvarchar(max)
SET #string = N'என்$பெயர்#PIN#ஆகிறது##என்$பெயர்#KUL#ஆகிறது'
SET #string = replace(#string,'##',' ') -- This will not work
Please let me know any possible solution
where abc-def-ghi-jkl are multilanguage character
Collation : SQL_Latin1_General_CP1_CI_AS
The point is UNICODE
You have to make sure, that you use unicode in all places
Literal strings must be started with an N everywhere
Try this
--This will come out with question marks
SELECT 'என்$பெயர்#PIN#ஆகிறது##என்$பெயர்#KUL#ஆகிறது';
--And this is the correct output
SELECT N'என்$பெயர்#PIN#ஆகிறது##என்$பெயர்#KUL#ஆகிறது';
--Here I replace one of the characters with a "%"
SELECT REPLACE(N'என்$பெயர்#PIN#ஆகிறது##என்$பெயர்#KUL#ஆகிறது',N'கி',N'%')
This works fine here...
UPDATE
Cannot verify this anymore, but it might be, that the output was wrong at the first try. I tried around with several collations. With this I got the wanted
SELECT N'YourString' COLLATE Indic_General_90_BIN;
After having used this, it was OK. So - but this is just guessing - it might be, that SQL Server had to learn this first...
If your code is like
DECLARE #string nvarchar(max) = N'என்$பெயர்#PIN#ஆகிறது##என்
SET #string = replace(#string,'##',' ')
results as
என்$பெயர்#PIN#ஆகிறது என்$பெயர்#KUL#ஆகிறது
if
DECLARE #string1 nvarchar(max) = 'என்$பெயர்#PIN#ஆகிறது##என்$பெயர்#KUL#ஆகிறது'
SET #string1 = replace(#string1,'##',' ')
then
???$?????#PIN#?????? ???$?????#KUL#??????
if
DECLARE #string2 varchar(max) = 'என்$பெயர்#PIN#ஆகிறது##என்$பெயர்#KUL#ஆகிறது'
SET #string2 = replace(#string2,'##',' ')
then
???$?????#PIN#?????? ???$?????#KUL#??????
if
DECLARE #string3 varchar(max) = N'என்$பெயர்#PIN#ஆகிறது##என்$பெயர்#KUL#ஆகிறது'
SET #string3 = replace(#string3,'##',' ')
then
???$?????#PIN#?????? ???$?????#KUL#??????
if you declares string as nvarchar you have to give N' before the string otherwise unicodes will not work.

how to split ntext datatype data to store in database

I have a column of type ntext called Emp_details_list, and it consists of data like
emp1###emp2###emp3...
At most it has 20 thousand characters as string and I am storing in that column and I need to split it and save in other table EmpDet and in other column (Single_Emp_det) but while splitting I can't cast ntext as nvarchar so am using a local variable and declared as nvarchar(max) and splitting but I can store only 8000 character only if I have 8001 characters it showing exception because it can't store so how can I store whole ntext data in other column using splitting concept in SQL Server
So you are probably stuck with Sql server 2000. If you can't use nvarchar(max), one possible way is to may be use substring function and copy your ntext to manageable chunks of varchar(8000) in a loop. In each iteration, save the 'part of chunk after the last #', to be used in next iteration. So you basically loop over your table, within that loop again loop over the ntext field value in chunks of 8k and do the rest. Hope it is clear enough.
As others already mentioned you can easily store 20000 characters in nvarchar(max). You are probably doing something wrong when converting these types.
Here is an example of converting from and to nvarchar(max) that clearly shows how can you store 20000 characters there.
DECLARE #v1 nvarchar(max)
DECLARE #v2 nvarchar(max)
create table #textExample
(
id int,
t1 ntext
)
declare #count int
set #v1 = ''
SET #count = 0
while #count < 20000
begin
set #v1 = #v1 + '1'
set #count = #count + 1
end
--converting nvarchar(max) to ntext
insert into #textExample
values (1, CONVERT(ntext,#v1))
select * from #textExample
-- converting ntext back to nvarchar(max)
SET #v2 = CONVERT(nvarchar(max), (select t1 from #textExample where id = 1))
select #v2, LEN(#v2)
drop table #textExample

Mistake in Sql query while splitting string

What mistake I am making in this sql query
Declare #str Varchar(100) = 'asasa,bsasas,csasa,dsczxvvc'
declare #d varchar(2)=','
SELECT
RIGHT(LEFT(#str,Number-1),
CHARINDEX(#d,REVERSE(LEFT(#d+#str,Number-1))))
FROM
master..spt_values
WHERE
Type = 'P' AND Number BETWEEN 1 AND LEN(#str)
AND SUBSTRING(#str,Number,1) = #d
Expected Result
(No column name)
asasa
bsasas
csasa
dsczxvvc
Actual Result
(No column name)
asasa
bsasas
csasa
Your AND SUBSTRING(#str, Number, 1) = #d is forcing a comma to be at the end of dsczxvvc...there isn't one. asasa,bsasas,csasa,dsczxvvc, works.
add one more comma at the end of string
you can directly add comma in the string like = "asasa,bsasas,csasa,dsczxvvc,"
or
handle this thing in sql side.
Declare #str Varchar(100)
set #str = 'asasa,bsasas,csasa,dsczxvvc'
declare #d varchar(2)
set #d =','
set #str = #str + ','
SELECT
RIGHT(LEFT(#str,Number-1),
CHARINDEX(#d,REVERSE(LEFT(#d+#str,Number-1))))
FROM
master..spt_values
WHERE
Type = 'P' AND Number BETWEEN 1 AND LEN(#str)
AND SUBSTRING(#str,Number,1) = #d
This is because since the last string portion does not have the seperator at the end of the string
If you add the following code just before the SELECT statement, it will work
set #str = #str + #d
There are many split functions on the web, you can use one of them actually.
Split string using CLR function
Split using XML
SQL Server split string function

LPAD in SQL Server 2008

I can't see a function like LPAD in SQL Server 2008. For example how can I convert the following queries into T-SQL?
select LPAD(MY_VALUE,2,' ')) VALUE
FROM MY_TABLE
Basically pad it with the number of characters you are intending to select and then right the string.
Select right(replicate(' ',2) + YourFieldValue,2) from YourTable
You can use the space function instead of replicate, space(number_of_spaces), replicate just allows you to pad with alternative characters.
Manual calculations can be annoying to apply inside queries. Luckily, we can create a function:
CREATE FUNCTION LPAD
(
#string VARCHAR(MAX), -- Initial string
#length INT, -- Size of final string
#pad CHAR -- Pad character
)
RETURNS VARCHAR(MAX)
AS
BEGIN
RETURN REPLICATE(#pad, #length - LEN(#string)) + #string;
END
GO
(Please replace VARCHAR with NVARCHAR to your liking, or use an alternative algorithm.)
Then:
SELECT dbo.LPAD(MY_VALUE, 2, ' ') VALUE
FROM MY_TABLE
Should work since SQL Server 2005.
I've come up with a LPAD and RPAD function where you can use a characterstring for the pad-part.
They should work the same as the DB2 versions.
Here's the LPAD:
CREATE FUNCTION dbo.LPAD
(
#string NVARCHAR(MAX), -- Initial string
#length INT, -- Size of final string
#pad NVARCHAR(MAX) -- Pad string
)
RETURNS VARCHAR(MAX)
AS
BEGIN
RETURN SUBSTRING(REPLICATE(#pad, #length),1,#length - LEN(#string)) + #string;
END
GO
And here is the RPAD:
CREATE FUNCTION dbo.RPAD
(
#string NVARCHAR(MAX), -- Initial string
#length INT, -- Size of final string
#pad NVARCHAR(MAX) -- Pad string
)
RETURNS VARCHAR(MAX)
AS
BEGIN
RETURN #string + SUBSTRING(REPLICATE(#pad, #length),1,#length - LEN(#string));
END
GO
I needed something similar but I couldn't use '+' because then it was interpreted as an addition between the numbers '0000000000' and [seq_no]. So I used concat instead and it worked fine.
select right (concat(replicate('0', 10), next value for seq_no), 10);

Resources