Create query with new column concatenate based on CASE/IIF criterias - sql-server

I have four columns in a table. The table identifies the packaging amounts per box. The four columns are -
ID
PerCase
InnerCarton
PerPack
I want query and create 2 columns ID & Condensed
Column condensed should result in "perCase/InnerCarton/PerPack"
there are many IDs where the InnerCarton is null, so I want the condensed column to show "PerCase/PerPack"
I tried this -
SELECT ID,
CAST(IIf([Items_UOM].[InnerCase] Is Not Null
,[Items_UOM].[PerCase] & '/' & [Items_UOM].[InnerCase] & '/' & [Items_UOM].[PerPack]
,[Items_UOM].[PerCase] & '/' & [Items_UOM].[PerPack]) AS varchar(25))
FROM Items_UOM;
I am getting an error message - Conversion failed when converting the varchar value '/' to data type smallint.

You have several things going on here not quite correct. First, to combine strings you use + not &. Second, you have datatype conversion issues because your columns are tinyint and you can't just add characters to add without an explicit conversion. You can also simplify this by using ISNULL or COALESCE instead of IIF and being forced to repeat the logic.
This should work for you.
SELECT ID,
convert(varchar(25), [Items_UOM].[PerCase]) + ISNULL('/' + [Items_UOM].[InnerCase], '') + '/' + convert(varchar(25), [Items_UOM].[PerPack])
FROM Items_UOM;

& is the binary and operator, not a string concatenation operator.
If CONCAT_NULL_YIELDS_NULL is set you could use + to concatenate the values with the slash and concat() to build the overall string. As with + the concatenation gets NULL if one operand is null the slash gets sort of eliminated for NULLs. concat() however replaces NULLs with an empty string, so the overall result isn't NULL if there are NULL values.
If the values are integers you need to convert them to a string them prior using them in the + as otherwise the + is interpreted as an arithmetic plus and results in the engine trying to convert the '/' to a number, which of course fails.
SELECT id,
concat(convert(varchar(max), items_uom.innercase) + '/',
convert(varchar(max), items_uom.percase) + '/',
convert(varchar(max), items_uom.perpack)
FROM items_uom;

Related

MSSQL: varchar to float conversion error in insert query

This is something that has puzzled me.
I have a SP with a TRY-CATCH and if it fails it should insert a record in an error log table with a message and some codes.
This is how it looks like:
INSERT INTO [Errors]
([application]
,[message]
,[extra])
VALUES
('MySP'
,ERROR_MESSAGE()
,'InvNum=' + str(#inumber) + ' -- InvId=' + str(#IID) + ' -- Error Num: ' + str(ERROR_NUMBER()) + ' -- Error Line: ' + str(ERROR_LINE()))
The problem is that every time it tries to run this query it produces a varchar to float conversion error. It doesn't make sense for me because all the values passed in the last column are being converted to string.
Any idea?
Instead of using the STR function on several values and then concatenating the string with the string concatenation operator, use the CONCAT function. It is pretty flexible with regards to what datatypes you pass into it and it should produce the same expected result.
INSERT INTO [Errors] ([application],[message],[extra])
VALUES (
'MySP'
, ERROR_MESSAGE()
, CONCAT('InvNum=',
#inumber,
' -- InvId=',
#IID,
' -- Error Num: ',
ERROR_NUMBER(),
' -- Error Line: ',
ERROR_LINE()
)
)
The problem is that according to the doc, the STR function "Returns character data converted from numeric data". In other words, the parser knows that the STR function requires numeric parameters, so it is trying to convert all of your arguments into floats first and then the STR function will change them into strings.
Personally, I almost never use the STR function because of stuff like this, rather I prefer to use either CAST(.. AS ..) or CONVERT(..) because they 1) care less about the input data type and 2) can produce any output data type based on the parameters. So rather than worry about which function I use to convert from data type (A) to data type (B), I always use the same function (CAST or CONVERT) and just have to worry about getting the parameters right.
Yes, it is true that CAST and CONVERT are a lot clunkier, longer and uglier, but if you just always use CONVERT than you only have to worry about how CONVERT works (also, CONVERT is super-general, you can use it for almost any scalar type conversion).

I'm having problems trying to correct a conversion issue in sql server 2016

I have a case statement where I'm trying to SUM multiple column int values and then format the summed value to '00000015700+' as an example but getting a conversion error in SQL Server 2016.
Here is the error:
Conversion failed when converting the varchar value '00000015700+' to
data type int.
Here is my code :
CASE
WHEN x.Code = 'WRITPREM' AND x.[Description] = 'NEW POLICY' THEN RIGHT('00000000000' + CAST(REPLACE((sum(x.totalPolicy_BIN) + sum(x.totalPolicy_COL) + sum(x.totalPolicy_OTC) + sum(x.totalPolicy_PDM) + sum(x.totalPolicy_MED) +sum(x.totalPolicy_PIP) + sum(x.totalPolicy_REN) + sum(x.totalPolicy_TOW) + sum(x.totalPolicy_UBI) + sum(x.totalPolicy_UPD)),'.','') as varchar(12)) + '+',12)END as TEST
Any help/direction would be appreciated. Thanks.
One of the fields that you are sum()ing contains the value with a "+" sign. As a result, SQL Server cannot convert the value to an integer in order to sum(). It seems you are applying the function on a non-numeric column(s). So you have unexpected data in at least one of those columns. Try eliminating some of the sum() columns to figure out which column contains the offending data. Ideally, you'd have the correct data types on each column and not run into this issue.
You have reversed the REPLACE and CAST commands. You should CAST the value to string, then REPLACE the decimal point and add your plus sign to the end, then take the RIGHT(..., 12) of that value.

how to increment nvarchar type in MSSQL

I have a table Tab1 with one of the column being ID ofNvarchar(80) [MSSQL] . I would like to have a variable as with initial value= 00100000 and then increment it by 00100001,00100002,00100003 and so on .later use it to fetch tab1.id from this variable in a loop. Can any one help me with this?
I'll start by saying that if you want an easy-to-increment variable, NVARCHAR isn't exactly the way to go; but I'll also assume you have a reason for doing this.
That being said, incrementing the value is as easy as:
SELECT CAST(<column_name> AS INT) + 1 FROM Tab1;
To insert the value with leading zeroes, you're going to need to do some concatenation:
SELECT '00' + CAST(CAST(<column_name AS INT) + 1 AS NVARCHAR(80)) FROM Tab1;
Just FYI, SQL Server will automatically try to convert the NVARCHAR value to an INTEGER value when you try adding 1, so you could technically shorten this to:
SELECT '00' + CAST(<column_name> + 1 AS NVARCHAR(80));
If you're eventually expecting to reach values which override those two leading zeroes, you're also going to need to take that into account later on. There are several ways that you could do this. Among the simplest:
SELECT RIGHT('00000' + CAST(<column_name> + 1 AS NVARCHAR(80)),8);

SQL: Fix for CSV import mistake

I have a database that has multiple columns populated with various numeric fields. While trying to populate from a CSV, I must have mucked up assigning delimited fields. The end result is a column containing It's Correct information, but also contains the next column over's data- seperated by a comma.
So instead of Column UPC1 containing "958634", it contains "958634,95877456". The "95877456" is supposed to be in the UPC2 column, instead UPC2 is NULL.
Is there a way for me to split on the comma and send the data to UPC2 while keeping UPC1 data before the comma in tact?
Thanks.
You can do this with string functions. To query the values and verify the logic, try this:
SELECT
LEFT(UPC1, CHARINDEX(',', UPC1) - 1),
SUBSTRING(UPC1, CHARINDEX(',', UPC1) + 1, 1000)
FROM myTable;
If the result is what you want, turn it into an update:
UPDATE myTable SET
UPC1 = LEFT(UPC1, CHARINDEX(',', UPC1) - 1),
UPC2 = SUBSTRING(UPC1, CHARINDEX(',', UPC1) + 1, 1000);
The expression for UPC1 takes the left side of UPC1 up to one character before the comma.
The expression for UPC2 takes the remainder of the UPC1 string starting one character after the comma.
The third argument to SUBSTRING needs some explaining. It's the number of characters you want to include after the starting position of the string (which in this case is one character after the comma's location). If you specify a value that's longer than the string SUBSTRING will just return to the end of the string. Using 1000 here is a lot easier than calculating the exact number of characters you need to get to the end.

Right pad a string with variable number of spaces

I have a customer table that I want to use to populate a parameter box in SSRS 2008. The cust_num is the value and the concatenation of the cust_name and cust_addr will be the label. The required fields from the table are:
cust_num int PK
cust_name char(50) not null
cust_addr char(50)
The SQL is:
select cust_num, cust_name + isnull(cust_addr, '') address
from customers
Which gives me this in the parameter list:
FIRST OUTPUT - ACTUAL
1 cust1 addr1
2 customer2 addr2
Which is what I expected but I want:
SECOND OUTPUT - DESIRED
1 cust1 addr1
2 customer2 addr2
What I have tried:
select cust_num, rtrim(cust_name) + space(60 - len(cust_name)) +
rtrim(cust_addr) + space(60 - len(cust_addr)) customer
from customers
Which gives me the first output.
select cust_num, rtrim(cust_name) + replicate(char(32), 60 - len(cust_name)) +
rtrim(cust_addr) + replicate(char(32), 60 - len(cust_addr)) customer
Which also gives me the first output.
I have also tried replacing space() with char(32) and vice versa
I have tried variations of substring, left, right all to no avail.
I have also used ltrim and rtrim in various spots.
The reason for the 60 is that I have checked the max length in both fields and it is 50 and I want some whitespace between the fields even if the field is maxed. I am not really concerned about truncated data since the city, state, and zip are in different fields so if the end of the street address is chopped off it is ok, I guess.
This is not a show stopper, the SSRS report is currently deployed with the first output but I would like to make it cleaner if I can.
Whammo blammo (for leading spaces):
SELECT
RIGHT(space(60) + cust_name, 60),
RIGHT(space(60) + cust_address, 60)
OR (for trailing spaces)
SELECT
LEFT(cust_name + space(60), 60),
LEFT(cust_address + space(60), 60),
The easiest way to right pad a string with spaces (without them being trimmed) is to simply cast the string as CHAR(length). MSSQL will sometimes trim whitespace from VARCHAR (because it is a VARiable-length data type). Since CHAR is a fixed length datatype, SQL Server will never trim the trailing spaces, and will automatically pad strings that are shorter than its length with spaces. Try the following code snippet for example.
SELECT CAST('Test' AS CHAR(20))
This returns the value 'Test '.
This is based on Jim's answer,
SELECT
#field_text + SPACE(#pad_length - LEN(#field_text)) AS RightPad
,SPACE(#pad_length - LEN(#field_text)) + #field_text AS LeftPad
Advantages
More Straight Forward
Slightly Cleaner (IMO)
Faster (Maybe?)
Easily Modified to either double pad for displaying in non-fixed width fonts or split padding left and right to center
Disadvantages
Doesn't handle LEN(#field_text) > #pad_length
Based on KMier's answer, addresses the comment that this method poses a problem when the field to be padded is not a field, but the outcome of a (possibly complicated) function; the entire function has to be repeated.
Also, this allows for padding a field to the maximum length of its contents.
WITH
cte AS (
SELECT 'foo' AS value_to_be_padded
UNION SELECT 'foobar'
),
cte_max AS (
SELECT MAX(LEN(value_to_be_padded)) AS max_len
)
SELECT
CONCAT(SPACE(max_len - LEN(value_to_be_padded)), value_to_be_padded AS left_padded,
CONCAT(value_to_be_padded, SPACE(max_len - LEN(value_to_be_padded)) AS right_padded;
declare #t table(f1 varchar(50),f2 varchar(50),f3 varchar(50))
insert into #t values
('foooo','fooooooo','foo')
,('foo','fooooooo','fooo')
,('foooooooo','fooooooo','foooooo')
select
concat(f1
,space(max(len(f1)) over () - len(f1))
,space(3)
,f2
,space(max(len(f2)) over () - len(f2))
,space(3)
,f3
)
from #t
result
foooo fooooooo foo
foo fooooooo fooo
foooooooo fooooooo foooooo

Resources