array_length() and cardinality() of an empty array return one of array size - sql

I have a table like :
CREATE TABLE psdc_psr
(
id bigint not null,
available_region_code character varying(255)[],
is_valid bigint,
)
I want usearray_length(), cardinality() or available_region_code ='{}' to select empty available_region_code columns but it failed, the length return one.
Why does this happen and how to solve this problem.

I don't know what reason causes this problem. Maybe like jjanes say in the comments the array has a non-printing character.
In the last, I use (CAST(ARRAY_TO_JSON(available_region_code) AS VARCHAR) IN ('[null]', '[""]')) to check empty array which learn from answer of Zone in question(How to check if an array is empty in Postgres).
The result on blow:

for a similar issue I had in presto based SQL, I created a case statement like:
case when available_region_code[1] = '' then 0 else cardinality(available_region_code) end as cardinality
Not sure if this helps in your use case, but it resulted in 0's for my empty arrays, and the correct counts for all others.

Related

Big Query SQL check if an array is null otherwise return 0

In big query, I am trying to show the array only if the array is not empty and else we return 0. The field "url" is an array with a type of string, however I am having difficulty implementing the logic. Side note I will not be able to use a where filter to filter the data but rather keep the original data and just perform a check on the field and have a placeholder of 0 is it's empty.
WITH temp_ as(
SELECT
ASE_IDD,
REGEXP_EXTRACT_ALL(
DESCRIPTION,
r"regex_placeholder") as url
FROM
table)
SELECT ASE_IDD, IF ( (url is not NULL), url, 0) from temp_
right not it does not work even though it should any help would be appreciated :)
here is my error:
1::SQL_ANALYSIS_ERROR: No matching signature for function IF for argument types: BO
I know what the error means but I don't what things I could do to solve it. I know my url is an array but is there any other way of comparison that will not use if or nullif or is there any other function that could help me solve this? SO please don't close my question I'm just looking for extra information I might have missed.
All values of the single column of the returned results should be of the same type. Therefore we cannot return both ARRAY-type (url array) and INT-type (digit 0) in the same column. We can convert both to STRING-type instead. Try array_length and to_json_string:
SELECT ASE_IDD, IF(array_length(url) > 0, to_json_string(url), "0") from temp_

ORA-01722: invalid number in column with numbers only?

I did a rather easy view to return only rows where there is number is CONTRACT_ID column. CONTRACT_ID has data type number(8).
CREATE OR REPLACE VIEW cid AS
SELECT *
FROM transactions
WHERE contract_id IS NOT NULL
AND LENGTH(contract_id) > 0;
View works just fine until I scroll down to row ~2950 where I get ORA-01722. Same thing happens if I want to export data to Excel, my file gets only ~2950 rows instead of expected ~20k.
Any idea what might be causing this and how to resolve this issue?
Many thanks!
You wrote too much SQL.. The following will provide all the results you require:
CREATE OR REPLACE VIEW cid AS
SELECT *
FROM transactions
WHERE contract_id IS NOT NULL
You can't LENGTH() a number - a number is either null or it's a value, so you don't need this kind of check.
Passing a number to LENGTH() will turn it into a string first, i.e. LENGTH(TO_CHAR(numbercolumn)). You don't even need a LENGTH() check for null strings, as to oracle NULL string and a zero length string are equivalent, and calling LENGTH() on an empty string or a null, will return null, not 0 (so LENGTH(myNullStr) = 0 doesnt work out; it's not comparing 0 = 0, it's comparing null = 0 and null compared with anything is always false).
The only time this seems to cause confusion is when the string columns in the table are CHAR types rather than VARCHAR types, and people forget that assigning an empty string to a CHAR causes it to become space padded out to the CHAR length hence, not a zero length string any more
First of all, you should remove redundant condition about length(), it's senseless. I'm not sure how it can produce such error, but check whether error disappered after it.
If no, replace star (*) to some field names, say, contract_id. If it will fix error - it would appoint that error source somewhere into removed fields (say, if generated column used).
I cannot imagine how error can be still alive after that, by if so, I'd tried to move it into other tablespace and add into fields list a call of logging function which stores rowid's of rows read - thus check which row produces error.

Using Substring, within ISNULL in TSQL returns unexpected number of characters for the field

My field in my SKU table
(BI.dbo.SKU.phl5) is varchar(15)
However below code returns just 3 characters 'Unc' for the null fields in my table while it should return 'Uncategorized'. How to solve that?
ISNULL(SUBSTRING(BI.dbo.SKU.phl5,0,3),'Uncategorized') AS phl1
ISNULL(CAST(SUBSTRING(BI.dbo.SKU.phl5,0,3) AS VARCHAR(13)),'Uncategorized') AS phl1
The size of the return type of SUBSTRING isn't clearly documented that I can find, but the problem is that the type of ISNULL is the type of the first expression, which is clearly coming back as VARCHAR(3) since you are truncating it to 3 characters.
ISNULL docs
Try this
CASE WHEN BI.dbo.SKU.phl5 IS NULL THEN 'Uncategorized'
ELSE SUBSTRING(BI.dbo.SKU.phl5,0,3)
END AS phl1

SQL - Conditionally joining two columns in same table into one

I am working with a table that contains two versions of stored information. To simplify it, one column contains the old description of a file run while another column contains the updated standard for displaying ran files. It gets more complicated in that the older column can have multiple standards within itself. The table:
Old Column New Column
Desc: LGX/101/rpt null
null Home
Print: LGX/234/rpt null
null Print
null Page
I need to combine the two columns into one, but I also need to delete the "Print: " and "Desc: " string from the beginning of the old column values. Any suggestions? Let me know if/when I'm forgetting something you need to know!
(I am writing in Cache SQL, but I'd just like a general approach to my problem, I can figure out the specifics past that.)
EDIT: the condition is that if substr(oldcol,1,5) = 'desc: ' then substr(oldcol,6)
else if substr(oldcol,1,6) = 'print: ' then substr(oldcol,7) etc. So as to take out the "desc: " and the "print: " to sanitize the data somewhat.
EDIT2: I want to make the table look like this:
Col
LGX/101/rpt
Home
LGX/234/rpt
Print
Page
It's difficult to understand what you are looking for exactly. Does the above represent before/after, or both columns that need combining/merging.
My guess is that COALESCE might be able to help you. It takes a bunch of parameters and returns the first non NULL.
It looks like you're wanting to grab values from new if old is NULL and old if new is null. To do that you can use a case statement in your SQL. I know CASE statements are supported by MySQL, I'm not sure if they'll help you here.
SELECT (CASE WHEN old_col IS NULL THEN new_col ELSE old_col END) as val FROM table_name
This will grab new_col if old_col is NULL, otherwise it will grab old_col.
You can remove the Print: and Desc: by using a combination of CharIndex and Substring functions. Here it goes
SELECT CASE WHEN CHARINDEX(':',COALESCE(OldCol,NewCol)) > 0 THEN
SUBSTRING(COALESCE(OldCol,NewCol),CHARINDEX(':',COALESCE(OldCol,NewCol))+1,8000)
ELSE
COALESCE(OldCol,NewCol)
END AS Newcolvalue
FROM [SchemaName].[TableName]
The Charindex gives the position of the character/string you are searching for.
So you get the position of ":" in the computed column(Coalesce part) and pass that value to the substring function. Then add +1 to the position which indicates the substring function to get the part after the ":". Now you have a string without "Desc:" and "Print:".
Hope this helps.

Conditionally branching in SQL based on the type of a variable

I'm selecting a value out of a table that can either be an integer or a nvarchar. It's stored as nvarchar. I want to conditionally call a function that will convert this value if it is an integer (that is, if it can be converted into an integer), otherwise I want to select the nvarchar with no conversion.
This is hitting a SQL Server 2005 database.
select case
when T.Value (is integer) then SomeConversionFunction(T.Value)
else T.Value
end as SomeAlias
from SomeTable T
Note that it is the "(is integer)" part that I'm having trouble with. Thanks in advance.
UPDATE
Check the comment on Ian's answer. It explains the why and the what a little better. Thanks to everyone for their thoughts.
select case
when ISNUMERIC(T.Value) then T.Value
else SomeConversionFunction(T.Value)
end as SomeAlias
Also, have you considered using the sql_variant data type?
The result set can only have one type associated with it for each column, you will get an error if the first row converts to an integer and there are strings that follow:
Msg 245, Level 16, State 1, Line 1
Conversion failed when converting the nvarchar value 'word' to data type int.
try this to see:
create table testing
(
strangevalue nvarchar(10)
)
insert into testing values (1)
insert into testing values ('word')
select * from testing
select
case
when ISNUMERIC(strangevalue)=1 THEN CONVERT(int,strangevalue)
ELSE strangevalue
END
FROM testing
best bet is to return two columns:
select
case
when ISNUMERIC(strangevalue)=1 THEN CONVERT(int,strangevalue)
ELSE NULL
END AS StrangvalueINT
,case
when ISNUMERIC(strangevalue)=1 THEN NULL
ELSE strangevalue
END AS StrangvalueString
FROM testing
or your application can test for numeric and do your special processing.
You can't have a column that is sometimes an integer and sometimes a string. Return the string and check it using int.TryParse() in the client code.
ISNUMERIC. However, this accepts +, - and decimals so more work is needed.
However, you can't have the columns as both datatypes in one go: you'll need 2 columns.
I'd suggest that you deal with this in your client or use an ISNUMERIC replacement
IsNumeric will get you part of the way there. You can then add some further code to check whether it is an integer
for example:
select top 10
case
when isnumeric(mycolumn) = 1 then
case
when convert(int, mycolumn) = mycolumn then
'integer'
else
'number but not an integer'
end
else
'not a number'
end
from mytable
To clarify some other answers, your SQL statement can't return different data types in one column (it looks like the other answers are saying you can't store different data types in one column - yours are all strign represenations).
Therefore, if you use ISNUMERIC or another function, the value will be cast as a string in the table that is returned anyway if there are other strigns being selected.
If you are selecting only one value then it could return a string or a number, however your front end code will need to be able to return the different data types.
Just to add to some of the other comments about not being able to return different data types in the same column... Database columns should know what datatype they are holding. If they don't then that should be a BIG red flag that you have a design problem somewhere, which almost guarantees future headaches (like this one).