SQL Statement Meaning - sql

Can someone tell me what this SQL statement is doing? Break it down as to what each part of the statement is doing.
convert(char(11),(field name 1 + right('0' + cast(field name 2 as varchar(2),2))

convert(char(11),(field_name_1 + right('0' + cast(field_name_2 as varchar(2),2))
convert() (documentation https://technet.microsoft.com/en-us/library/ms187928(v=sql.105).aspx):
Tells the sql server to convert the value in the second parameter to the type given in the first parameter.
char(11):
Tells the sql server that the value behind the command needs to become a character field type, of a maximum length of 11 characters.
after the comma we have the following
(field_name_1 + right('0' + cast(field_name_2 as varchar(2),2)
field_name_1 corresponds to the field on the table you're reading. It will get the value of that field and put it there.
+ means append string. Append the value that follows after the + to the value before the +
for example
'foo' + 'bar' = 'foobar'
'foo' + 'baz = 'foobaz'
So in this case whatever follows behind the + should be appended tot he value of field_name_1
right is a function, get N characters starting from the end of the string(documentation https://learn.microsoft.com/en-us/sql/t-sql/functions/right-transact-sql)
within this function a lot happens. But the first part before the comma '0' + cast(field_name_2 as varchar(2) is the string right is called upon, and the 2 is the number of characters to select from it, starting from the end.
So if you have the following values fed into right
013
03
044
you'll end up with
13
03
44
Now we have this part:
'0' + cast(field_name_2 as varchar(2)`
'0' is a string literal. This is just a string, of length one, that contains the character 0
+ means append string. Append the value that follows after the + to the value before the +
So in this case, anything that follows the + will be appended to 0.
example:
'0' + 'foo' = '0foo'
'0' + '1' = '01'
cast(field_name_2 as varchar(2))
In your code you're actually missing a closing ) here, might cause you some trouble.
Basically what it does it takes the value of field_name_2 which is probably of the type integer(just guessing) and converts it to the type of varchar, with a maximum length of 2(guessing the number will never exceed 99).
so a number with value of 1 gets turned into a string with the character for the value 1, namely '1'.
2 = '2';
33 = '33';
42 = '42';
this combined with the previous part would yield
'0' + '2' = '02';
'0' + '33' = '033';
'0' + '42' = '042';
that will be fed into the right(value, 2); which will result in
right('02', 2) = '02';
right('033', 2) = '33';
right('042', 2) = '42';
which will be appended to the value of field_name_1
'foobar' + '02' = 'foobar02';
which is then converted in a character type string value of maximum 11 characters long.

Related

CAST(somenumber as VARCHAR(10)) + somestring returns Error converting data type varchar to numeric

I'm trying to combine a min and max salary with a hyphen for display in a report. I feel like I've done this a hundred times but I still can't figure out why I'm getting the "Error converting data type varchar to numeric" especially since I'm trying to convert a numeric to varchar not the other way around.
amt_exp_formatted = CASE
WHEN a.class_code IN ('9997','9998','9999') THEN 0
--ELSE CAST(e.min_sal as VARCHAR(10)) + '-' + CAST(e.max_sal as VARCHAR(10))
ELSE CONVERT(VARCHAR(1), 1) + CONVERT(VARCHAR(1), 'a')
END
In the above example if I use 'a' I get the error. If I change 'a' to '9' then it works AND it appends 9 to the 1 (i.e. 19) rather than adding them together which is exactly what I want but with a character string. I've tried both CAST and CONVERT with no luck. I know I shouldn't need the second CONVERT on the letter 'a' but I was just trying to force the data types to be the same just in case. I have no doubt at all I'm missing something simple but I can't seem to get it so I figured it wouldn't hurt to ask the community.
Thank you!
A case expression returns one value with a determinate type. If any returned fork returns a number, then number it is. And strings get converted.
So, be sure you are returning a string in all cases:
(CASE WHEN a.class_code IN ('9997', '9998', '9999')
THEN '0'
ELSE CONCAT(e.min_sal, '-', e.max_sal)
END)
CONCAT() automatically converts the arguments to strings.
This is becuase you are mixing the data type. in the first part of case you were returning 0 while in the else part you're converting it to varchar(). - you can try the below returning 0 as also varchar
amt_exp_formatted = CASE
WHEN a.class_code IN ('9997','9998','9999') THEN '0'
--ELSE CAST(e.min_sal as VARCHAR(10)) + '-' + CAST(e.max_sal as VARCHAR(10))
ELSE CONVERT(VARCHAR(1), 1) + CONVERT(VARCHAR(1), 'a')
END

SQL - string comparison ignores space

This query:
SELECT CASE WHEN 'abc ' = 'abc' THEN 1 ELSE 0 END
Returns 1, even though 'abc ' clearly is not equal to 'abc'. Similarly,
SELECT CASE WHEN 'abc ' LIKE '%c' THEN 1 ELSE 0 END
Also returns 1. However, a very similar query:
SELECT * FROM #tempTable WHERE Name LIKE '%c'
Did not return a row where Name = 'abc '.
SQL Server 2008 R2, Windows 7 & 2008 R2, x64.
= ignores trailing space
len ignores training space
like does not ignore trailing space
SELECT CASE WHEN 'abc ' = 'abc' and DATALENGTH('abc ') = DATALENGTH('abc')
THEN 1 ELSE 0 END
You can assert DATALENGTH is not relevant but it is still the solution.
Turns out that the Name column was NVARCHAR (even though it contained ASCII characters only) and NVARCHAR behaves differently than VARCHAR:
SELECT CASE WHEN N'abc ' LIKE 'abc' THEN 1 ELSE 0 END
Returns 0, ditto for column instead of literal. The following does return 1 still:
SELECT CASE WHEN N'abc ' = 'abc' THEN 1 ELSE 0 END
So = and LIKE work differently, another peculiar difference.
If you need to compare things in this way but are restricted because your columns are of data type VARCHAR, something like this will basically fill the trailing space with an 'X' which will accomplish a failed comparison:
DECLARE #1 VARCHAR(5), #2 VARCHAR(5)
SET #1 = 'ABC '
SET #2 = 'ABC'
IF REPLACE(#1,' ','X') = REPLACE(#2,' ','X')
PRINT 'Equal'
ELSE
PRINT 'Not Equal'
Not rocket science, but at least a work around if you encounter a similar situation that you need to deal with :)
TA, I am not sure how you got zero by simply mentioning as unicode(N). I run your query and it giving me 1 only.
You can compare the LEN('abc ') and DATALENGTH('abc ') and can use those as per you requirement or you can replace the trailing space with some character to solve your problem.
I had a similar issue with a nvarchar column and wanted to fix the data so I did the following to find the data
select 'x' + username + 'x' from aspnet_users
where 'x' + username + 'x' <> 'x' + rtrim(username) + 'x'
The where clause compares the username as is with the trimmed version
'x1234 x' <> 'x1234x'
To fix the data I just did an update
update aspnet_Users
set username = rtrim(username)
where 'x' + username + 'x' <> 'x' + rtrim(username) + 'x'

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.

tsql returns the right answer only when I specify the criteria in the where clause

I have some sql that will not return the rows I need unless I specify that as a criteria in the where clause. If I uncomment the part below that is commented out, it will give me the rows I want. If I leave it commented out, those rows are not returned in my result set.
Does this make sense? Can anyone see anything I'm doing wrong? Thanks.
SELECT
RTRIM(c.comp2) + '-' + l.Loc_Name,
MAX(RTRIM(g.mega_location_num) + '-' + g.mega_location_name)
FROM
mkt_share_comp c, gldm_location g, mkt_share_locs l
WHERE
RTRIM(c.comp1) = g.location_num
AND c.comp2 = l.Loc_No
AND LEN(c.comp2) = 5 AND c.is_deleted = 0 AND l.is_deleted = 0
--and g.mega_location_num = '450'
GROUP BY
RTRIM(c.comp2) + '-' + l.Loc_Name
ORDER BY
MAX(RTRIM(g.mega_location_num) + '-' + g.mega_location_name)
This comparison:
MAX(RTRIM(g.mega_location_num) + '-' + g.mega_location_name)
Will be doing a MAX based on the string value that you're constructing. So if there are any g.mega_location_num values which start with a digit greater than 4 (or start with 4 and have a second digit greater than 5, etc), then that value will be the MAX value returned.
To start to fix this, I would first switch to the ANSI join style that Kuya has suggested. I would then consider including an appropriate ROW_NUMBER() expression to locate the "genuine" maximum value from the g table and to be able to retrieve multiple columns from that maximal row (to allow the string construction to proceed)

How can I generate ID with Prefix, Numeric Number and suffix?

I want to generate an ID in MSSQL Server 2008. Which will be Prefix + Numeric Number + suffix Like 'PV#000001#SV'. Which will be user defined (depends on configuration ) prefix, numeric length, suffix and starting number. Numeric number will be increased every time.
I tied to write this :
Blockquote
ALTER PROCEDURE [dbo].[spACC_SELECT_VOUCHER_NUMBER]
#COMPANY_ID uniqueidentifier,
#VOUCHER_TYPE INT
AS BEGIN
DECLARE #IS_AUTOMETIC BIT = (SELECT VOUCHER_CONFIG_NUMBERING_METHOD
FROM ACC_VOUCHER_CONFIG WHERE
ACC_VOUCHER_CONFIG.VOUCHER_CONFIG_VALUE=#VOUCHER_TYPE )
IF(#IS_AUTOMETIC=1)
BEGIN
SELECT CASE WHEN SUBSTRING(V.VOUCHER_CODE, 7, 23) IS NULL
THEN CASE WHEN VC.VOUCHER_CONFIG_PREFIX IS NULL THEN '' ELSE VC.VOUCHER_CONFIG_PREFIX END +
RIGHT ('0000000000000'+ CAST( VC.VOUCHER_CONFIG_BEGINING_NUMBER AS VARCHAR), VC.VOUCHER_CONFIG_NUMERIC_WIDTH) +
CASE WHEN VC.VOUCHER_CONFIG_SUFFIX IS NULL THEN '' ELSE VC.VOUCHER_CONFIG_SUFFIX END
ELSE CASE WHEN VC.VOUCHER_CONFIG_PREFIX IS NULL THEN '' ELSE VC.VOUCHER_CONFIG_PREFIX END +
RIGHT ('0000000000000'+ CAST((CAST( SUBSTRING(V.VOUCHER_CODE, 7, 23) AS INT)+1) AS VARCHAR), VC.VOUCHER_CONFIG_NUMERIC_WIDTH) +
CASE WHEN VC.VOUCHER_CONFIG_SUFFIX IS NULL THEN '' ELSE VC.VOUCHER_CONFIG_SUFFIX END
END AS VOUCHER_CODE FROM ACC_VOUCHER_CONFIG VC
LEFT OUTER JOIN ACC_VOUCHER V ON VC.VOUCHER_CONFIG_VALUE = V.VOUCHER_TYPE
WHERE VC.COMPANY_ID=#COMPANY_ID AND VC.VOUCHER_CONFIG_VALUE=#VOUCHER_TYPE
END
END
When I change the numeric length / suffix its not working.
Thanks
Nahid
For the six-digit number you're struggling with, add leading zeroes like this:
SELECT RIGHT('00000'+ CONVERT(VARCHAR,Num),6) AS NUM FROM your_table
Where Num is your sequential number.
This prepends 5 zeroes and then takes the right 6 characters from the resulting string.
A more detailed writeup of custom ID generation is here:
http://www.sqlteam.com/article/custom-auto-generated-sequences-with-sql-server
My suggestion would be to store just a number in the database (i.e. an int) and format the ID client side with tools that are better suited for it (i.e. a programming language that has sprintf or equivalent string formatting).