Insert a negative value with minus sign at end - sql

I want to insert a value into an sql server 2008 table.
The value are like 20.00- , 10.00-
The minus sign is at the end of the value.
How can I achieve this?

How about using something like this?
SELECT REPLACE(CAST(-456.00 AS VARCHAR(10)),'-','') + '-'
Where 456.00 is your value

You could insert raw data into a staging table first. Then you could either convert the values in the staging table and insert them afterwards into the actual table, or insert and convert at the same time.
Here's how you could go about the conversion.
For every input value, you would need to check if it has a minus. If it does, then one character should be deleted at the last position and one character should be inserted at the first position. Otherwise nothing should be deleted or inserted.
So, essentially you can have an indication in the form of 1 or 0 and use that number to determine how many characters to insert or delete.
There are various methods of obtaining that 1/0 result.
For instance, you could take the input value's last character as a substring and use CHARINDEX to search for - within that substring:
CHARINDEX('-', LEFT(InputValue, LEN(InputValue)))
If the last character of InputValue is '-', the CHARINDEX will return 1, otherwise it will return 0.
Another method, also using CHARINDEX, would be to go like this:
CAST(CHARINDEX('-', InputValue) AS bit)
If InputValue has a minus, CHARINDEX will return a positive result and CAST will convert it to 1. If there is no minus, CHARINDEX will give you a 0, which will stay 0 after the cast.
Now you can use the expression's result to determine:
whether to delete the last character or not:
STUFF(InputValue, LEN(InputValue), CAST(CHARINDEX('-', InputValue) AS bit), '')
and
whether to prefix the value with a '-':
REPLICATE('-', CAST(CHARINDEX('-', InputValue) AS bit))
That is, the complete expression is this:
REPLICATE('-', CAST(CHARINDEX('-', InputValue) AS bit)) +
STUFF(InputValue, LEN(InputValue), CAST(CHARINDEX('-', InputValue) AS bit), '')
In the final statement you could also use CROSS APPLY to avoid repetition of the emphasised sub-expression, something aloong the lines of this (assuming you will choose to do insertion + processing):
INSERT INTO dbo.TargetTable (columns)
SELECT
...
REPLICATE('-', x.HasMinus) + STUFF(InputValue, LEN(InputValue), x.HasMinus, ''),
...
FROM dbo.StagingTable
CROSS APPLY (SELECT CAST(CHARINDEX('-', InputValue) AS bit)) AS x (HasMinus)
;

It is long but :
select IIF(ISNUMERIC(IIF(RIGHT(RTRIM('20.55-'), 1) = '-', '-' + REPLACE('20.55-', '-',''), '20.55-')) = 1, CONVERT(decimal(7,3), IIF(RIGHT(RTRIM('20.55-'), 1) = '-', '-' + REPLACE('20.55-', '-',''), '20.55-')), NULL)

Simply :
Select CASE WHEN LEFT(InputValue,1) = '-' THEN '-' ELSE '' END + REPLACE(InputValue,'-','')
You may need to Cast it as money (or numeric or decimal)

Related

Does the SQL CASE statement treat variables differently from columns?

I have the following code in a stored procedure and am trying to conditionally format a calculated number based on its length (if the number is less than 4 digits, pad with leading zeros). However, my case statement is not working. The "formattedNumber2" result is the one I'm looking for.
I'm assuming the case statement treats the variable strangely, but I also don't know of a way around this.
DECLARE #Number int = 5
SELECT
CASE
WHEN (LEN(CONVERT(VARCHAR, #Number)) > 4)
THEN #Number
ELSE RIGHT('0000' + CAST(#Number AS VARCHAR(4)), 4)
END AS formattedNumber,
LEN(CONVERT(VARCHAR, #Number)) AS numberLength,
RIGHT('0000' + CAST(#Number AS VARCHAR(4)), 4) AS formattedNumber2
I get the following results when I run the query:
formattedNumber numberLength formattedNumber2
-------------------------------------------------
5 1 0005
SQL DEMO
The problem is you are using different data type on your case , integer and string. So the CASE stay with the first type he find and convert the rest.
CASE WHEN (LEN(convert(VARCHAR, #Number)) > 4) THEN convert(VARCHAR, #Number)
This can be done a lot easier with format() since version 2012.
format(n,
'0000')
And that would also handle negative values, which your current approach apparently doesn't.
Prior 2012 it can be handled with basically replicate() and + (string concatenation).
isnull(replicate('-',
-sign(n)), '')
+
isnull(replicate('0',
4
-
len(cast(abs(n) AS varchar(10)))
),
'')
+
cast(abs(n) AS varchar(10))
(It targets integer values, choose a larger length for the varchar casts for bigint.)
db<>fiddle

Replacing empty string in SQL using SELECT

I'm trying to replace empty strings with a value and I can't seem to find the best way to do this.
The issue is that SOME values in the phone_number column are in a format without the numbers. For example ( ) -
I want to replace those empty values with 000-0000. I tried to use the CASE WHEN function but that doesn't seem to address the problem. The COALESCE IFNULL won't work because technically the values aren't NULL just incomplete. I'm thinking perhaps the CASE WHEN function would work if I could figure out how to format the empty values correctly.
Here is an example of the code
SELECT
phone_column,
CASE
WHEN phone_column = '() -'
THEN '000-000'
ELSE SUBSTRING(phone_colum, 6, 8)
END AS Phone
FROM
client_table
ORDER BY
linkid_
declare #test table(ph varchar(20))
insert into #test
select '( ) -'
UNION
select ''
UNION
select '(123)-456-7890'
select case
when replace(ph,'( ) -','')='' then '000-000'
else substring(ph,6,8)
end
from #test
if you want to search in a varchar then use LIKE this would help you in using expressions. For instance, in your case phone_column = '() -' would be phone_column LIKE '() -%' this will match any string that begins with () -. if you do phone_column = '() -' then it will only match the exact same string.
Any how, I'm not sure why you want to take this road, while you can validate the current numbers and try to only store the valid ones, as storing invalid numbers would be useless.
I'll give you an example,
to validate phone numbers, you first take out any existed formats (parentheses, dashes, spaces) then you'll be end up with a whole number with 10 or 7 digits. depends on your way of storing phone numbers. any numbers less than that would be invalid.
To remove the formats :
SELECT REPLACE(REPLACE(REPLACE(REPLACE(Number,'(',''),')',''),'-',''),' ','')
Now you will have only numbers, which will be easier to handle.
Like this :
SELECT
phone_column
FROM (SELECT REPLACE(REPLACE(REPLACE(REPLACE(phone_column,'(',''),')',''),'-',''),' ','') phone_column FROM client_table) D
PS : Some countries phone numbers begins with 0, if your numbers don't
begin with 0, then you would cast the number to BIGINT, which will
remove any leading zeros.
Now, you can use the case to validate the numbers and do whatever you like with them.
SELECT
CASE
WHEN LEN(phone_column) = 10
THEN '(' + SUBSTRING(phone_column,1,3) + ') ' + SUBSTRING(phone_column, 3,3) + '-' + SUBSTRING(phone_column, 6,4)
ELSE '(000) 000-0000'
END Phone
FROM (SELECT REPLACE(REPLACE(REPLACE(REPLACE(phone_column,'(',''),')',''),'-',''),' ','') phone_column FROM client_table) D

SQL String Manipulation and character replacement

I have a database with a list of old ItemID's that need updating to a new format.
The old format is of the form 8046Y and the new format moves the 4th digit to the end and prepends a hyphen and adds a 0 if it's a single digit. The old format also uses alpha characters when the number goes over 9 for example 464HB where the H represents 17. I also need to add a 1 to the beginning of the new format. All this can be done with string manipulation in SQL I hope.
Some examples:
8046Y becomes 1804Y-06
464HB becomes 1464B-17 (H = 17)
Can anyone give me some pointers as to how to go about this in SQL?
I got as far as:
select '1' + LEFT(ItemID, 3) + RIGHT(ItemID,1) + '-' + '0' + SUBSTRING(ItemID,3,1) from items
But the conversion from a=10 to z=36 stumped me
Try this:
select
'1'
+ left(#str,3)
+ right(#str,1)
+ '-'
+ case
when substring(#str,4,1) like '%[0-9]%' 1 then right('00' + substring(#str,4,1),2)
else cast(10 + ascii(substring(#str,4,1))-ascii('A') as varchar(2))
end
Explanation: If the 4th character is a digit, then do not change the value and append it after padding with a zero. Otherwise, use ASCII to get the ASCII value for that character, get it's difference with the value for 'A' and add the offset of 10.
Demo
Since I don't know if there are any other special character to consider except 'H' only included this single character.
DECLARE #val CHAR(5) = '464HB'
SELECT #val, '1' + LEFT(#val,3)+SUBSTRING(#val,5,1)+'-'+CASE WHEN +SUBSTRING(#val,4,1)='H' THEN '17' ELSE '0'+SUBSTRING(#val,4,1) END
select '1' + LEFT(ItemID, 3) + RIGHT(ItemID,1) + '-'
+CASE RIGHT(LEFT(ItemID,1),2)
WHEN 'a' then 10
WHEN 'b' THEN 11
etc...
END [NewItemID]
from items
Just add the appropriate cases in that format.
I do it only for the challenge, i dont recommend to use
DECLARE #id varchar(5) = '8046Y'
--SET #id = '464HB'
SELECT
'1' +
LEFT(#id, 3) +
RIGHT(#id, 1) +
'-' +
CASE WHEN ISNUMERIC(RIGHT(LEFT(#id, 4), 1)) = 1 THEN
RIGHT(LEFT(#id, 4), 1)
ELSE
RIGHT('00' + CONVERT(VARCHAR, ASCII(RIGHT(LEFT(#id, 4), 1)) - 64 + 9), 2)
END
-64 for the Start of ASCII A and +9 for your convention
Personally, I'd create a function for it.
Create a variable to handle the new value.
Manipulate the positions through SUBSTRING, you can also use RIGHT or LEFT
When adding zeros in single digit numbers, just do conditional statement
Regarding the conversion of letters to numbers(e.g. letter H), the converted value of the first letter is 65 assuming it's all capital. So, A=65, B=66, H=72 and so on. Use this data in manipulating the values. Uhm, I'll give you my thoughts but you can optimize it (since I don't have lots of time).
Taking your example of H=17, so A=10. Just subtract 55 in the conversions. So H=72(-55) becomes 17. This is applicable to all letters (in uppercase only).
I think this much is more than enough to guide you. Hope this would help.

Remove leading zeros

Given data in a column which look like this:
00001 00
00026 00
I need to use SQL to remove anything after the space and all leading zeros from the values so that the final output will be:
1
26
How can I best do this?
Btw I'm using DB2
This was tested on DB2 for Linux/Unix/Windows and z/OS.
You can use the LOCATE() function in DB2 to find the character position of the first space in a string, and then send that to SUBSTR() as the end location (minus one) to get only the first number of the string. Casting to INT will get rid of the leading zeros, but if you need it in string form, you can CAST again to CHAR.
SELECT CAST(SUBSTR(col, 1, LOCATE(' ', col) - 1) AS INT)
FROM tab
In DB2 (Express-C 9.7.5) you can use the SQL standard TRIM() function:
db2 => CREATE TABLE tbl (vc VARCHAR(64))
DB20000I The SQL command completed successfully.
db2 => INSERT INTO tbl (vc) VALUES ('00001 00'), ('00026 00')
DB20000I The SQL command completed successfully.
db2 => SELECT TRIM(TRIM('0' FROM vc)) AS trimmed FROM tbl
TRIMMED
----------------------------------------------------------------
1
26
2 record(s) selected.
The inner TRIM() removes leading and trailing zero characters, while the outer trim removes spaces.
This worked for me on the AS400 DB2.
The "L" stands for Leading.
You can also use "T" for Trailing.
I am assuming the field type is currently VARCHAR, do you need to store things other than INTs?
If the field type was INT, they would be removed automatically.
Alternatively, to select the values:
SELECT (CAST(CAST Col1 AS int) AS varchar) AS Col1
I found this thread for some reason and find it odd that no one actually answered the question. It seems that the goal is to return a left adjusted field:
SELECT
TRIM(L '0' FROM SUBSTR(trim(col) || ' ',1,LOCATE(' ',trim(col) || ' ') - 1))
FROM tab
One option is implicit casting: SELECT SUBSTR(column, 1, 5) + 0 AS column_as_number ...
That assumes that the structure is nnnnn nn, ie exactly 5 characters, a space and two more characters.
Explicit casting, ie SUBSTR(column,1,5)::INT is also a possibility, but exact syntax depends on the RDBMS in question.
Use the following to achieve this when the space location is variable, or even when it's fixed and you want to make a more robust query (in case it moves later):
SELECT CAST(SUBSTR(LTRIM('00123 45'), 1, CASE WHEN LOCATE(' ', LTRIM('00123 45')) <= 1 THEN LEN('00123 45') ELSE LOCATE(' ', LTRIM('00123 45')) - 1 END) AS BIGINT)
If you know the column will always contain a blank space after the start:
SELECT CAST(LOCATE(LTRIM('00123 45'), 1, LOCATE(' ', LTRIM('00123 45')) - 1) AS BIGINT)
both of these result in:
123
so your query would
SELECT CAST(SUBSTR(LTRIM(myCol1), 1, CASE WHEN LOCATE(' ', LTRIM(myCol1)) <= 1 THEN LEN(myCol1) ELSE LOCATE(' ', LTRIM(myCol1)) - 1 END) AS BIGINT)
FROM myTable1
This removes any content after the first space character (ignoring leading spaces), and then converts the remainder to a 64bit integer which will then remove all leading zeroes.
If you want to keep all the numbers and just remove the leading zeroes and any spaces you can use:
SELECT CAST(REPLACE('00123 45', ' ', '') AS BIGINT)
While my answer might seem quite verbose compared to simply SELECT CAST(SUBSTR(myCol1, 1, 5) AS BIGINT) FROM myTable1 but it allows for the space character to not always be there, situations where the myCol1 value is not of the form nnnnn nn if the string is nn nn then the convert to int will fail.
Remember to be careful if you use the TRIM function to remove the leading zeroes, and actually in all situations you will need to test your code with data like 00120 00 and see if it returns 12 instead of the correct value of 120.

Most efficient method for adding leading 0's to an int in sql

I need to return two fields from a database concatenated as 'field1-field2'. The second field is an int, but needs to be returned as a fixed length of 5 with leading 0's. The method i'm using is:
SELECT Field1 + '-' + RIGHT('0000' + CAST(Field2 AS varchar),5) FROM ...
Is there a more efficient way to do this?
That is pretty much the way: Adding Leading Zeros To Integer Values
So, to save following the link, the query looks like this, where #Numbers is the table and Num is the column:
SELECT RIGHT('000000000' + CONVERT(VARCHAR(8),Num), 8) FROM #Numbers
for negative or positive values
declare #v varchar(6)
select #v = -5
SELECT case when #v < 0
then '-' else '' end + RIGHT('00000' + replace(#v,'-',''), 5)
Another way (without CAST or CONVERT):
SELECT RIGHT(REPLACE(STR(#NUM),' ','0'),5)
If you can afford/want to have a function in your database you could use something like:
CREATE FUNCTION LEFTPAD
(#SourceString VARCHAR(MAX),
#FinalLength INT,
#PadChar CHAR(1))
RETURNS VARCHAR(MAX)
AS
BEGIN
RETURN
(SELECT Replicate(#PadChar, #FinalLength - Len(#SourceString)) + #SourceString)
END
I would do it like this.
SELECT RIGHT(REPLICATE('0', 5) + CAST(Field2 AS VARCHAR(5),5)
Not necessarily all that "Easier", or more efficient, but better to read. Could be optimized to remove the need for "RIGHT"
If you want to get a consistent number of total strings in the final result by adding different number of zeros, here is a little bit modification (for vsql)
SELECT
CONCAT(
REPEAT('0', 9-length(TO_CHAR(var1))),
CAST(var1 AS VARCHAR(9))
) as var1
You can replace 9 by any number for your need!
BRD