SQL Server reducing the length of the string to 8000 characters - sql

I am trying to insert data in a table with column datatype as NTEXT. Ideally it should store more than 8000 characters, but the in my case it is reducing it to 8000 characters.
I am making the Insert Query at runtime in Procedure. Below is the sample query that procedure is making.
INSERT INTO TMPRESULTS SELECT ('A' + ',' + 'B' + ',' + 'C')
A,B,C, etc. are sample data and actual data will be identified at runtime with actual content crossing 8000 characters. Also the variable used to store the value are defined as 'NVARCHAR(MAX)'
However, when I try following query it does insert more than 8000 character in the table
INSERT INTO TMPRESULTS SELECT ('ABCdddd................')
I presume while I am trying to concat the data with '+' sign, sql server is reducing the length to 8000. I can't use CONCAT as data will be more than 256 columns/arguments.
Any idea, why it is doing so? Also, if someone can help with some alternate solution as I will have to make insert query at runtime.

This is documented in + (String Concatenation) (Transact-SQL) - Remarks:
If the result of the concatenation of strings exceeds the limit of
8,000 bytes, the result is truncated. However, if at least one of the
strings concatenated is a large value type, truncation does not occur.
For a varchar 8,000 bytes would be 8,000 characters, and for a nvarchar 4,000.
All your literal strings in the query INSERT INTO TMPRESULTS SELECT ('A' + ',' + 'B' + ',' + 'C') are non large value types (In fact, they are all a varchar(1)). If you CONVERT/CAST one of them to a varchar(MAX) this would solve the problem:
INSERT INTO TMPRESULTS
SELECT (CONVERT(varchar(MAX),'A') + ',' + 'B' + ',' + 'C');
if you want an nvarchar, make sure you declare your literal strings as a nvarchar too:
INSERT INTO TMPRESULTS
SELECT (CONVERT(nvarchar(MAX),N'A') + N',' + N'B' + N',' + N'C');

In SQL Server 2017 onwards, there is CONCAT_WS function to perform concatenation easily. You can also read about CONCAT
So, instead of this:
INSERT INTO TMPRESULTS SELECT ('A' + ',' + 'B' + ',' + 'C')
We can have below:
INSERT INTO TMPRESULTS SELECT CONCAT_WS(CAST(N',' AS NVARCHAR(MAX)),'A','B','C'))
I have put sample below from SQL Server 2017 for reference:
CREATE TABLE #tempValue(BigValue NVARCHAR(MAX))
INSERT INTO #tempValue
SELECT CONCAT_WS(CAST(N',' AS NVARCHAR(MAX)),REPLICATE('A',4000),REPLICATE('B',4000),REPLICATE('C',4000))
SELECT LEN(BigValue) FROM #tempValue -- 12002
Also, CONCAT_WS is better for below reasons:
If CONCAT_WS receives arguments with all NULL values, it will return
an empty string of type varchar(1).
CONCAT_WS ignores null values during concatenation, and does not add
the separator between null values.

Related

SQL Server : exploding CSV for SELECT statement

I have a table structure as below;
id txtName intReferences
------------------------------
1 Fred 1,4,6,444,56,43,
2 Sam 5,33,5904,43
3 Tom 1200
4 Samantha 43,44,888,99
I'd like to write a T-SQL query to return all the records based on a series of numbers provided.
For example, querying for 43 would return Fred, Sam and Samantha. The catch is, when querying for 3, it shouldn't return results for Sam or Samantha, given that that isn't the number in its entirety. Looking for a direct and whole number match.
The CSV value may end in a comma.
I've tried to use the "IN" statement, but it returns results if any portion of the number exists. Ideally trying to achieve without creating a function given some database restrictions.
Use string_split():
select t.*
from t cross apply
string_split(t.intReferences, ',') s
where s.value = '3';
Then, fix your data model so your are not storing integer values in strings. This is bad, bad, bad. Here are some reasons why:
Numbers should be stored as numbers, not strings (using the correct type).
SQL Server has lousy string manipulation functions.
Only one value should be stored in a column.
Foreign key relationships should be properly declared.
Resulting queries cannot be optimized to using indexes or partitions.
SQL has a great way to store lists. It is called a table not a string.
Clearly, the best way to accommodate this situation is to have properly normalized data.
Another method for querying the data with the current structure would be to check for comma + (your number) + comma. Something like this...
Declare #Temp Table(id int, txtName varchar(200), intReferences varchar(200))
Insert Into #Temp Values(1, 'Fred', '1,4,6,444,56,43,')
Insert Into #Temp Values(2, 'Sam', '5,33,5904,43')
Insert Into #Temp Values(3, 'Tom', '1200')
Insert Into #Temp Values(4, 'Samantha', '43,44,888,99')
Select *
From #Temp
Where ',' + intReferences + ',' like '%,' + '43' + ',%'
Select *
From #Temp
Where ',' + intReferences + ',' like '%,' + '3' + ',%'

Spaces in WHERE clause for SQL Server [duplicate]

This question already has answers here:
Why the SQL Server ignore the empty space at the end automatically?
(2 answers)
Closed 4 years ago.
I want to find out the records in which a certain column contains exactly one space and nothing else. So I wrote the first of the following queries:
select COUNT(*)
from mytable
where col = ' ' -- One space
select COUNT(*)
from mytable
where col = ' ' -- Two spaces
select COUNT(*)
from mytable
where col = ' ' -- Three spaces
However, all three queries return the exact same records. Does Microsoft SQL Server not distinguish between the amount of spaces? How can I query exactly for one, two or more spaces?
Yes, it ignores trailing spaces in comparisons.
You can try to append a delimiting character.
SELECT count(*)
FROM mytable
WHERE col + 'X' = ' X';
You can combine DATALENGTH clause with your query:
select COUNT(*)
from mytable
where col = ' '
and DATALENGTH(col) = 1
The link posted by Ivan Starostin in the comments of the OP provides a good explanation and I think it deserves a full answer instead of just a comment.
To summarize, try using LIKE instead of equality:
select COUNT(*)
from mytable
where col LIKE ' ' -- one space
And you can also use DATALENGTH to calculate how many bytes are in the field to double-check field length:
select col, DATALENGTH(col)
from mytable;
Please note that DATALENGTH will return a different value if col is a VARCHAR vs NVARCHAR. VARCHAR stores each character as 1 byte where NVARCHAR stores each character as 2 bytes since NVARCHAR is stored in Unicode.
You can replace the single space with a single character (for exampe §) and then put this character in your where condition:
declare #tmp table(col varchar(50))
insert into #tmp values
(' '),
(' '),
(' ')
select COUNT(*) as one_space_count
from #tmp
where replace(col,' ','§')='§'
select COUNT(*) as two_space_count
from #tmp
where replace(col,' ','§')='§§'
select COUNT(*) as three_space_count
from #tmp
where replace(col,' ','§')='§§§'
Results:

Concate Primary Keys in SQL

I want to concate Primary Keys of multiple tables in SQL directly. I used below query to concate three primary keys with a hyphen between them but the SQL skipped the hyphen and sum up the primary keys and result in a single value.
SELECT CID + '-' + RID + '-'+ CGID As [IdCombination] ...
where CID , RID and CGID are the Primary Keys of three SQL Tables.
How it skipped the string part in query ?
Any help would be highly appreciated.
Updated
For Example : The Values of CID , RID and CGID are 3 , 4, 3 respectively. It should be 3-4-3 but the result is 10.
What is happening? Remember that + means both addition and string concatenation. It so happens that - can be interpreted as a number (like -0), so SQL Server prefers to interpret the + as addition.
Normally, when you do this type of operation, the separation character cannot be interpreted as a number, and you just get an error. I am amused that you don't get an error in this case.
One method is to explicitly cast the values as strings:
SELECT CAST(CID as VARCHAR(255)) + '-' + CAST(RID + as VARCHAR(255)) '-'+ CAST(CGID as VARCHAR(255)) As [IdCombination]
In SQL Server 2012+, you can do this more simply using CONCAT():
SELECT CONCAT(CID, '-', RID, '-', 'CGID) As [IdCombination]
CONCAT() knows that everything should be a string.
Try this
SELECT 5 + '-' + 8
The output is 13. I must admit, that I did not expect this...
And now try this
SELECT CAST('-' AS INT)
The result is 0. As your select starts with an INT, SQL Server tries to do a summa of int values. As the single hyphen is casteable to int implicitly, this returns the summa of your values...
The solution, as pointed out by others is either a cast of your column values to a string type or the usage of CONCAT
I would need to see output, but I am assuming, some ID is stored as int and it is being counted, so you should use
SELECT Cast(CID as Varchar(50)) + '-' + Cast(RID as Varchar(50)) + '-'+ Cast(CGID as Varchar(50)) As [IdCombination]

Varchar to Number in sql

i have written a query in which i am fetching an amount which is a number like '50,000','80,000'.
select Price_amount
from per_prices
As these values contain ',' these are considered to be varchar.Requirement is to to print these as 'number' with ','
that is how can '50,000' be considered as number and not varchar
If a value has anything other than numbers in it, it is not an integer it is string containing characters. in your case you have a string containing character 5, 0 and ,.
If this is what is stored in your database and this is what you want to display then go ahead you do not need to change it to Integer or anything else. But if you are doing some calculations on these values before displaying them, Yes then you need to change them to an Integer values. do the calculation. Change them back to the varchar datatype to show , between thousands and hundred thousands and display/select them.
Example
DECLARE #TABLE TABLE (ID INT, VALUE VARCHAR(100))
INSERT INTO #TABLE VALUES
(1, '100,000'),(2, '200,000'),(3, '300,000'),(4, '400,000'),
(1, '100,000'),(2, '200,000'),(3, '300,000'),(4, '400,000')
SELECT ID, SUM(
CAST(
REPLACE(VALUE, ',','') --<-- Replace , with empty string
AS INT) --<-- Cast as INT
) AS Total --<-- Now SUM up Integer values
FROM #TABLE
GROUP BY ID
SQL Fiddle
you could combine the Replace and cast function
SELECT CAST(REPLACE(Price_amount, ',', '') AS int) AS Price_Number FROM per_prices
for more information visit 'replace', 'cast'
SQLFiddle

Convert comma-separated list of values into a single comma-separated string?

How to convert this:
('xxx','yyy','zzz')
Into this:
('xxx,yyy,zzz')
Using T-SQL?
DECLARE #x VARCHAR(32) = '''xxx'',''yyy'',''zzz''';
SELECT REPLACE(#x, ''',''', ',');
If all you want to do is concatenate then you can do:
SELECT #param1 + ',' + #param2 + ',' ... + #param30;
However that is just silly IMHO. This is like washing each of your socks separately.
I have to question what you're going to do with the value now... if these are separate entities why are they comma-separated in the first place? Perhaps you should look into table-valued parameters instead of this comma-separated values nonsense, then you can use the values in a set-based way right from the start.
by concatenating the values (which means individual columns)?
SELECT (col1 + ',' + col2+ ',' + col3)
FROM tableName