How to do a count of fields in SQL with wrong datatype - sql

I am trying to import legacy data from another system into our system. The problem I am having is that the legacy data is dirty- very dirty! We have a field which should be an integer, but sometimes is a varchar, and the field is defined as a varchar...
In SQL Server, how can I do a select to show those records where the data is varchar instead if int?
Thanks

If you want to find rows1 where a column contains any non-digit characters or is longer than 9 characters (either condition means that we cannot assume it would fit in an int, use something like:
SELECT * FROM Table WHERE LEN(ColumnName) > 9 or ColumnName LIKE '%[^0-9]%'
Not that there's a negative in the LIKE condition - we're trying to find a string that contains at least one non-digit character.
A more modern approach would be to use TRY_CAST or TRY_CONVERT. But note that a failed conversion returns NULL and NULL is perfectly valid for an int!
SELECT * FROM Table WHERE ColumnName is not null and try_cast(ColumnName as int) is null
ISNUMERIC isn't appropriate. It answers a question nobody has ever wanted to ask (IMO) - "Can this string be converted to any of the numeric data types (I don't care which ones and I don't want you to tell me which ones either)?"
ISNUMERIC('$,,,,,,,.') is 1. That should tell you all you need to know about this function.
1If you just want a count, as per the title of the question, then substitute COUNT(*) for *.

In SQL Server, how can I do a select to show those records where the data is varchar instead of int?
I would do it like
CREATE TABLE T
(
Data VARCHAR(50)
);
INSERT INTO T VALUES
('102'),
(NULL),
('11Blah'),
('5'),
('Unknown'),
('1ThinkPad123'),
('-11');
SELECT Data -- Per the title COUNT(Data)
FROM
(
SELECT Data,
cast('' as xml).value('sql:column("Data") cast as xs:int ?','int') Result
FROM T --You can add WHERE Data IS NOT NULL to exclude NULLs
) TT
WHERE Result IS NULL;
Returns:
+----+--------------+
| | Data |
+----+--------------+
| 1 | NULL |
| 2 | 11Blah |
| 3 | Unknown |
| 4 | 1ThinkPad123 |
+----+--------------+
That if you can't use TRY_CAST() function, if you are working on 2012+ version, I'll recommend that you use TRY_CAST() function like
SELECT Data
FROM T
WHERE Data IS NOT NULL
AND
TRY_CAST(Data AS INT) IS NULL;
Demo
Finally, I would say do not use ISNUMERIC() function because of (from docs) ...
Note
ISNUMERIC returns 1 for some characters that are not numbers, such as plus (+), minus (-), and valid currency symbols such as the dollar sign ($). For a complete list of currency symbols, see money and smallmoney (Transact-SQL).

Related

Why rand() in format function returns null?

I want to generate a 6 digit number in SQL Server, which first digit is allowed to be zero.
For generating a random 6 digit number I use this code:
round(rand()*power(10,6),0)
For making sure that it is a 6 character number I use as this example:
format(12345,'D6')
Which returns:
012345
But when I use below phrase it returns NULL
select format(round(rand()*power(10,6),0),'D6')
I was searching to find the cause, but I just understand that even format(rand()*power(10,6),'D6') returns null, while format(round(power(10,3),0),'D6') and select format(power(10,3),'D6') returns the answer.
It shows that the problem is neither about power() nor round(). The rand() function is the cause.
I use this code to solve my problem:
declare #num int = round(rand()*power(10,6),0)
select format(#num,'D6')
But I just want to know why rand() in format() returns null, I couldn't find the cause.
If you have any idea, I'll appreciate it.
Thanks.
The function rand()*power(10,6) returns a float.
When you put it into a variable type int you force the conversion to int.
We can do the same thing with cast(.. as int) as in
select format(cast(rand()*power(10,6)as int),'D6') which works correctly. (As the value is already a whole number there is no need to use round())
If we use a variable type float we get a null value:
declare #num float = round(rand()*power(10,6),0)
select format(#num,'D6')
| (No column name) |
| :--------------- |
| null |
The problem therefore occurs when we use format() with a float as argument.

Oracle - Map column data to a value

Let me first point out that my question is going to be very very close to this question: map-column-data-to-a-value-oracle
Please quickly read that one first.
Now in my case I need the exact same thing but not as the primary query. Instead I need the information as one part of my query.
I have this table:
someId | someValue | dataType
1 | 500 | 1
2 | someValue | 2
And I know that dataType "1" means "Integer". I also know the meaning of the other values in the dataType column.
So I want to select all entries in the table but have their dataTypes as their human readable values instead of their numbers:
Results:
1, 500, Integer
2, someString, String
Trying to apply the solution of the question I linked, I created a subquery like
SELECT
someId,
someValue,
(
SELECT CASE
WHEN dataType = 1 THEN 'INTEGER'
WHEN dataType = 2 THEN 'FLOAT'
WHEN dataType = 3 THEN 'TEXT'
ELSE 'DATE'
END
myTable
) as myDataType
I will get a subquery that returns more than 1 result and Oracle will complain.
Since I access the DB through SQL directly, I need a "pure SQL" solution. Otherwise I could just parse the value through a mapping, in say PHP. But that's not possible here. I am shooting some queries at a DB to try and gather information about the data and structure, which we don't know about. So only SQL is available.
Get rid of the subquery:
SELECT someId,
someValue,
CASE
WHEN dataType = 1 THEN 'INTEGER'
WHEN dataType = 2 THEN 'FLOAT'
WHEN dataType = 3 THEN 'TEXT'
ELSE 'DATE'
END as Datatype
from myTable

Conversion failed on inner join

I am trying to inner join a smallint field on a varchar field. I only need the integer values but I am getting an error. The varchar field has integers and strings. I do not need the ID field only the DESC.
I get an error:
Conversion failed when converting the varchar value 'AWOL' to data type smallint.
This is what the table look like:
==================================
|ID |DESC |
|==========|=====================|
|ACAMPROCAL|acamprosate calcium |
|----------|---------------------|
|BUPROPION |bupropion |
|----------|---------------------|
|1 |Other |
|----------|---------------------|
|4 |Expired |
|----------|---------------------|
|3 |Dschg |
|----------|---------------------|
|AWOL |Absence without Leave|
==================================
Here is the query I've tried but also commented out:
SELECT
CASE_NUM, LAST_NAME, FIRST_NAME, MI, '' AS NA,
DOB, SEX, [ADDRESS], '' AS NA, CITY, STATE, ZIP
--,CONVERT(SMALLINT, CONVERT(VARCHAR(55), CDTBL1.[DESC]))
--,CASE WHEN CDTBL1.ID BETWEEN 1 AND 99999 THEN CDTBL1.[DESC]
--END AS COUNTY
FROM
CDCLIENT
INNER JOIN
CDTBL1 ON CDCLIENT.ADDR_COUNTY_ID = CDTBL1.ID
Change
'ON CDCLIENT.ADDR_COUNTY_ID = '
to
'ON CAST(CDCLIENT.ADDR_COUNTY_ID as varchar) = '
You should check the datatypes of the columns you are joining on to be sure that they are the same type.
Generally I would think an ID column would be some type of int, but the table you provided above contains varchar values in the ID column as well.
There is a precedence to the datatypes in SQL and smallint is above varchar. There is an implicit conversion taking place that is causing the failure.
More info here: https://msdn.microsoft.com/en-us/library/ms190309.aspx
This is an issue with Implicit Conversions and SQL Server chose the wrong data to convert. Typically, when you need to compare different data types, it's usually best to explicitly convert one to another.
Microsoft has a nice table on what data types are allowed to implicitly and explicitly convert between.
If you want non-negative integers, then use logic like this:
select (case when CDTBL1.[DESC] not like '%[^0-9]%'
then convert(smallint, CDTBL1.[DESC])
end)
Note that you might also want to check the length and values of the field, to be sure you don't get an error.
In SQL Server 2012+, you can simplify this using try_convert():
select try_convert(smallint, CDTBL1.[DESC])
This returns NULL if an error would occur. But, it is not available in SQL Server 2008.

How do I cast a type to a bigint in MySQL?

CAST() seems to only work for BINARY,CHAR,DATE;DATETIME,DECIMAL,TIME,SIGNED,UNSIGNED.
I need to convert a hex string to a bigint, that is, I'd want:
SELECT CAST(CONV("55244A5562C5566354',16,10) AS BIGINT)
CONV() returns a string, so that's why I'm trying the convert it. I have 2 uses for this
Inserting data, e.g. INSERT INTO a(foo) SELECT CONV(bar,16,10) FROM ... Here foo is a bigint column, bar a varchar. Perhaps I could get away with the select statement being a string and let MySQL take care of it (?)
Returning data where the client will dynamically learn the data type of the column, SELECT CONV(bar,16,10) is no good as the client will handle it as a string.
SELECT CAST(CONV('55244A5562C5566354',16,10) AS UNSIGNED INTEGER);
What seems to be the problem? I've tested this conversion both on 64-bit and 32-bit system. Works fine. Note, that instead of doing hex to bin conversion, you can just treat the number as hexadecimal.
mysql> SELECT CAST(X'55244A5562C5566354' AS UNSIGNED);
+-----------------------------------------+
| CAST(X'55244A5562C5566354' AS UNSIGNED) |
+-----------------------------------------+
| 2614996416347923284 |
+-----------------------------------------+
1 row in set (0.00 sec)

T-SQL Parameters

I have the following table in SQL Server 2000:
TABLE_NAME | COLUMN_NAME | TYPE_NAME | PRECISION | LENGTH | SCALE |
test TestID int 10 4 0
test TestDecimal decimal 18 20 2
test TestFloat float 15 8 NULL
test TestMoney money 19 21 4
My question is, if I wanted to created a stored procedure that takes 4 parameters based on my table fields, how do I do this. I have this solution:
CREATE PROCEDURE TestProc ( #TestID int, #TestDecimal decimal, #TestFloat float, #TestMoney money )
AS
.....
.....
.....
GO
This works, except I think #TestDecimal loses its decimal portion, thus converting it into a whole number. Do I need to put #TestDecimal decimal(Precision,Scale) instead of just decimal? and if so, is there any other numeric datatypes that I need to specify this type of parameter encoding?
Yes, you need to specifc (18,2) for decimal/numeric
The same applies to float/real, (n)varchar, (n)char, (var)binary, datetime2 (missed any?)
A different precision, scale or length is in effect a different datatype and a conversion will occur.
Example question of why differenmt varchar lengths make different datatypes
Your parameter type must match the database column type. A database type is defined not only by its base type, but also by its actual length and precision, when it applies. TestDecimal id actualy DECIMAL(18,2) in your example.