Printing out box drawing characters (extended-ascii) in SSMS - sql

I want to print box-drawing character in Output messages in SSMS. It includes characters like e.g. ║ or ░ or ╬.
The full list of characters which I have in my mind can be found here.
When I am trying the following: PRINT '╬' it returns simply + while I am expecting ╬.
When I am executing SELECT ASCII('╬') it returns 43, but when I am executing SELECT CHAR(43) it returns (not surprisingly) +.
Is it related to collation? If so, how can I find which collation to use?

A simple literal in SQL-Server is - by default a CHAR / VARCHAR type. This type is 1-byte-encoded extended ASCII: The lower half is the plain latin character set, the upper half is depending on a collation. This means, there is very little support for non-standard characters.
The second character type is NCHAR / NVARCHAR. This is (almost) unicode, very close to utf-16. The actual encoding is two-byte encoded UCS-2. The support for non-standard characters is (almost) complete. Any literal starting with a N is treated as NCHAR / NVARCHAR:
Try this:
SELECT '╬',N'╬';
DECLARE #str1a VARCHAR(10)='╬';
DECLARE #str1b VARCHAR(10)=N'╬'; --The NVARCHAR literal is changed to VARCHAR
DECLARE #str2 NVARCHAR(10)=N'╬';
SELECT #str1a,#str1b,#str2;
The functions to get the code point and - vice versa - to get the character are two-folded too:
SELECT ASCII('a'), UNICODE(N'a')
,ASCII('╬'), UNICODE(N'╬')
,CHAR(97),NCHAR(97),CHAR(43),NCHAR(43)
,NCHAR(9580)--does not work with `CHAR`

You need to print then in Unicode, i.e. to prefix them with N:
PRINT N'╬'

Related

LTRIM RTRIM not working for Chinese string SQL

I have a column named Text which receives from the end user the following string:
'复合模头滤网 φ245 120目*300目 24×120目 '
Which includes a weird space, kind of larger than the regular space, at the end. However it has the same ASCII code as the normal space 32.
I used this SQL code to trim my string but always returning same string without trimming !!!!
LTRIM(RTRIM([Text]))
The solution is to try trim the the character with the ASCII code 32. The following code works perfectly:
TRIM(CHAR(32) from [ShortText])
To check it out if works , I tried it this way :
DECLARE #t TABLE(txt nvarchar(255));
INSERT INTO #t VALUES (TRIM(CHAR(32) from '复合模头滤网 φ245 120目*300目 24×120目 '));
SELECT txt, LEN((txt)), ASCII(RIGHT(txt,1)) AS ASCII_Char
--32=SPACE,--13 CR,--11 LF, 9-tab
FROM #t
This character is U+3000 IDEOGRAPHIC SPACE, and as documented, SQL Server by default only removes U+0020 SPACE.
You can use TRIM(... FROM in modern versions of SQL Server
DECLARE #t nvarchar(1000) = N'复合模头滤网 φ245 120目*300目 24×120目 ';
SELECT
DATALENGTH(#t) / 2 totalCharacters,
LEN(#t) totalCharactersTrimmed,
TRIM(#t) trimmedNormal,
DATALENGTH(TRIM(#t)) / 2 totaTrimmedNormal,
TRIM(NCHAR(0x3000) FROM #t) trimmedIdeographic,
TRIM(N' ' FROM #t) trimmedIdeographic,
DATALENGTH(TRIM(NCHAR(0x3000) FROM #t)) / 2 totalTrimmedIdeographic;
SELECT
UNICODE(NCHAR(0x3000)) unicodeNum,
ASCII(NCHAR(0x3000)) asciiNum;
db<>fiddle
You claim it has the same ASCII code, however that is just because ASCII does not have an exact character for it. If you use the UNICODE function, you will see the difference, as the fiddle shows.
For such characters as these, you must make sure to use the nvarchar data type, and the NCHAR and UNICODE functions.

try to concatenate 2 strings, result ends in a lot of spaces

select CONCAT(convert(char, 123), 'sda');
Or
select convert(char, 123) + 'sda'
Or
select ltrim(convert(char, 123) + 'sda')
Output is:
How can I get the output without those spaces?
The problem here is 2 fold. Firstly that you are converting to a char, which is a fixed width datatype, and secondly that you aren't defining the length of your char, therefore the default length is used. For CAST and CONVERT that's a char(30).
So, what you have to start is convert(char, 123). This converts the int 123 to the fixed width string '123 '. Then you concatenate the varchar(3) value 'sda' to that, resulting in '123 sda'. This is working exactly as written, but clearly not as you intend.
The obvious fix would be to use a varchar and define a length, such as CONCAT(CONVERT(varchar(5),123),'sda') which would return '123sda', however, all of the CONCAT function's parameters are a string type:
string_value
A string value to concatenate to the other values. The CONCAT function requires at least two string_value arguments, and no more than 254 string_value arguments.
This means you can simply just pass the value 123 and it'll be implicitly cast to a string type: CONCAT(123,'sda').
To reiterate my comment's link too: Bad Habits to Kick : Declaring VARCHAR without (length)
You are using char while you probably want [n]varchar(...): the former pads the string with white spaces, while the latter does not:
concat(convert(varchar(10), 123), 'sda');
But simpler yet: concat() forces the conversion of its arguments to the correct datatype by default, so this should do it:
concat(123, 'sda')
First, in SQL Server, never us char or related string definitions without a length. SQL Server requires a length and the default depends on the context. If you depend on the default length your code has a bug just waiting to happen.
Second, char is almost never what you want. It is a fixed length string, with shorter strings padded with spaces.
If you want an explicit conversion use varchar, variable length strings:
select convert(varchar(255), 123) + 'sda'
Or dispense with the explicit conversion and use concat():
select concat(123, 'sda')
As the others have already pointed out the root cause of the issue, if you cannot edit the datatype, you can always use SELECT CONCAT(TRIM(CONVERT(char,123)),'sda'). Although it's highly recommended to either use varchar(n) or give exclusive length of char as it is kind of pointless to create fixed length string and then reduce the length by using TRIM. varchar(30) would perfectly fit in here as the length can still NOT exceed the 30 symbols, but would not use all the length if the string is shorter.
Lets refer to Microsoft docs:
When n isn't specified in a data definition or variable declaration statement, the default length is 1. If n isn't specified when using the CAST and CONVERT functions, the default length is 30.
Reference: https://learn.microsoft.com/en-us/sql/t-sql/data-types/char-and-varchar-transact-sql?view=sql-server-ver15#remarks
So, You have Convert(char, 123), and you did not specify the n for char, so your code is equal to Convert(char(30), 123).
Now it is clear why you have many space characters. To resolve the problem simply use variant length character datatypes such as varchar instead, however I recommend you to always use character datatypes with length. (Same as what #GordonLinoff posted: https://stackoverflow.com/a/63467483/1666800)
select convert(varchar, 123) + 'sda'

Oracle 11g hextoraw sql query results

So, I have a table called mams_folder , where primary key is mams_folder_id.
Now, its type is raw. I am representing keys in hexadecimal string.
Following queries were run on sql developer.
Now, I run these queries :
select * from mams_folder f where f.mams_folder_id= hextoraw('EEA12100F39D100384D2080020F03012'); //Works fine
select * from mams_folder f where f.mams_folder_id= 'EEA12100F39D100384D2080020F03012';//Surprisingly works fine too. Why ?
select * from mams_folder f where f.mams_folder_id= hextoraw('5426deaf924642bb9a38dc0b5be87ed6'); //Works fine as expected
select * from mams_folder f where f.mams_folder_id= '5426deaf924642bb9a38dc0b5be87ed6'; //Returns no rows as expected
Both are valid primary keys. '5426deaf924642bb9a38dc0b5be87ed6' was newly inserted in database.
Why does db returns answer to second query but returns null for the last ?
Does it have to do something with db caching ?
Update :
Ok, I came to know that if I am using primary keys in uppercase hex string, then even without using hextoraw() , queries work fine (as we can see above). However when smaller case is used, hextoraw() becomes compulsary to use else empty result is shown. Why ?
I believe what you are seeing stems from implicit/explicit type conversion mechanics when inserting by literal or hextoraw then later predicating against a literal.
Formal Hexadecimal is 0123456789ABCDEF (uppercase), radix 16, though there is tooling (both in Oracle and elsewhere) to recognize character strings containing 0123456789abcdefABCDEF (case insensitive) as hex.
HEXTORAW is case-insensitive and accepts lower-case hex. But the returned raw value will be formal hex.
As an example, running the following:
SELECT HEXTORAW('5426deaf924642bb9a38dc0b5be87ed6') AS HEX FROM DUAL;
Gives formal upper-case hex
HEX
5426DEAF924642BB9A38DC0B5BE87ED6
And the following will of course fail, as it contains a non-hex char g
SELECT HEXTORAW('5426geaf924642bb9a38dc0b5be87ed6') FROM DUAL;
ORA-01465: invalid hex number
As will implicit conversion when inserting the above literal into a raw field. RAW requires hex.
For the queries against mams_folder table, I believe the queries with lower-case literal predicates find no matches because when predicating with a string literal, the ensuing type conversion to compare RAW and VARCHAR2 winds up attempting to match formal hex char against lower-case literal char. (It does not convert the provided literal to raw, but compares the hex to the literal)
Since HEXTORAW converts any input string to formal hex in the conversion process, it ends up with a different comparison than the plain literal would anyway, even if it were comparing char instead of raw.
So the simple predicate that matches the converted (upper-case) RAW against a lower-case literal will result in no matches. But when comparing an upper-case literal against the RAW, the formal hex used in comparison happens to match the upper-case string literal and the predicate is fulfilled.
Here's an example:
CREATE TABLE mams_folder (mams_folder_id RAW(32));
Then add the test data. One item is added as an upper-case literal, one added as a lower-case literal, relying on oracle to do any needed type conversion implicitly
INSERT INTO mams_folder VALUES ('EEA12100F39D100384D2080020F03012');
INSERT INTO mams_folder VALUES ('5426deaf924642bb9a38dc0b5be87ed6');
Then just query to see how things look initially. No hextoraw involved yet.
SELECT * FROM MAMS_FOLDER;
MAMS_FOLDER_ID
EEA12100F39D100384D2080020F03012
5426DEAF924642BB9A38DC0B5BE87ED6
Note the printed value for the inserted literal '5426deaf924642bb9a38dc0b5be87ed6'.
Now the conversion comparing raw to upper-case literal matches.
In this query:
SELECT MAMS_FOLDER_ID, 'EEA12100F39D100384D2080020F03012' AS TARGET FROM MAMS_FOLDER;
We can see that the first row matches the converted raw with the literal.
MAMS_FOLDER_ID TARGET
EEA12100F39D100384D2080020F03012 EEA12100F39D100384D2080020F03012
5426DEAF924642BB9A38DC0B5BE87ED6 EEA12100F39D100384D2080020F03012
With the implicit comparisons matching the formal hex from the RAW against the literal rather than converting the literal to a raw, UPPER would work just fine in a predicate as well.
SELECT * FROM MAMS_FOLDER F WHERE F.MAMS_FOLDER_ID = UPPER('5426DEAF924642BB9A38DC0B5BE87ED6');
MAMS_FOLDER_ID
5426DEAF924642BB9A38DC0B5BE87ED6

What is the max value of a CHAR?

I was wondering what the max char value is in sql? I noticed in C# this \uFFFF, but when I use that value to compare a string SQL renders it as an empty string I think.
The table is in SQL_Latin1_General_CP1_CI_AS if that matters.
There is a deep misconception of what is ascii...
ASCII is a 7bit code (0 to 127) where the characters are fix
the 8th bit offers this range a second time (128 to 255). In this area the characters are depending on codepages and collations.
Thinking of CHAR as a BYTE (8 bit in memory) is misleading...
Try this, both return a captial A
SELECT CHAR(65) COLLATE Latin1_General_CI_AS
SELECT CHAR(65) COLLATE Arabic_CI_AS
The code 255 renders with Latin1_General_CI_AS as ÿ, with the arabic collation there seems to be no printable character, hence the question mark.
SELECT CHAR(255) COLLATE Latin1_General_CI_AS
SELECT CHAR(255) COLLATE Arabic_CI_AS
So in short: SQL renders it as an empty string is not true. This is depending on your settings
Did you checked Documentation as it clearly says
char [ ( n ) ]
Fixed-length, non-Unicode string data. n defines the
string length and must be a value from 1 through 8,000. The storage
size is n bytes. The ISO synonym for char is character.
Numerically, the answer is 255. CHAR has a potential range of 0 to 255. It is an 8-bit code unit for the character encoding configured for the field (which it might inherit from the table or database).
Whether 255 is a valid code unit and is a complete codepoint, and which character it represents, and its sort order (is that what you meant by max?), depends on the collation. (A collation specifies a character encoding and sort order.)
Oh, if you are going to compare SQL datatypes to others, NVARCHAR and C#'s char and .NET's Char all use UTF-16 as the character encoding.

Retrieving MS SQL database size in culture independent format

sp_helpdb returns strings like '50000.255 MB' in the db_size column.
These strings are culture-dependent; the above string will mean 2 different things in US and Germany (in the latter, the dot char is used as a group separator, similar to the comma in US).
Is there another method which returns a numeric value, culture-independent?
Use YourDB;
SELECT SUM(Size / 128.0) As FileSize from sys.database_files;
This returns the size in MB as a numeric, you should be able to do what you like with it from there.
Note: size returns the number of 8KB pages in a given database file.
http://msdn.microsoft.com/en-us/library/ms174397.aspx
I do not think it is possible. The SP sp_helpdb uses str to convert the numeric size to varchar and there is nothing in the documentation (that I can find) that can make str use , instead of . as decimal symbol. Using set language does not help.
Workaround as suggested by Martin in comment
select replace(str(sum(convert(dec(17,2),size)) / 128,10,2) +' MB', '.', ',')
from sys.database_files