cross-dbms way to check if string is numeric - sql

Ok, I have this field: code varchar(255). It contains some values used in our export routine like
DB84
DB34
3567
3568
I need to select only auto-generated (fully numeric) fields
WHERE is_numeric(table.code)
is_numeric() checks if code field contains only positive digits.
Can you propose anything that will work both under mysql 5.1 and oracle 10g?

Below are three separate implementations for each of SQL Server, MySQL and Oracle. None use (or can) the same approach, so there doesn't seem to be a cross DBMS way to do it.
For MySQL and Oracle, only the simple integer test is show; for SQL Server, the full numeric test is shown.
For SQL Server:
note that isnumeric('.') returns 1.. but it can not actually be converted to float. Some text like '1e6' cannot be converted to numeric directly, but you can pass through float, then numeric.
;with tmp(x) as (
select 'db01' union all select '1' union all select '1e2' union all
select '1234' union all select '' union all select null union all
select '1.2e4' union all select '1.e10' union all select '0' union all
select '1.2e+4' union all select '1.e-10' union all select '1e--5' union all
select '.' union all select '.123' union all select '1.1.23' union all
select '-.123' union all select '-1.123' union all select '--1' union all
select '---1.1' union all select '+1.123' union all select '++3' union all
select '-+1.123' union all select '1 1' union all select '1e1.3' union all
select '1.234' union all select 'e4' union all select '+.123' union all
select '1-' union all select '-3e-4' union all select '+3e-4' union all
select '+3e+4' union all select '-3.2e+4' union all select '1e1e1' union all
select '-1e-1-1')
select x, isnumeric(x),
case when x not like '%[^0-9]%' and x >'' then convert(int, x) end as SimpleInt,
case
when x is null or x = '' then null -- blanks
when x like '%[^0-9e.+-]%' then null -- non valid char found
when x like 'e%' or x like '%e%[e.]%' then null -- e cannot be first, and cannot be followed by e/.
when x like '%e%_%[+-]%' then null -- nothing must come between e and +/-
when x='.' or x like '%.%.%' then null -- no more than one decimal, and not the decimal alone
when x like '%[^e][+-]%' then null -- no more than one of either +/-, and it must be at the start
when x like '%[+-]%[+-]%' and not x like '%[+-]%e[+-]%' then null
else convert(float,x)
end
from tmp order by 2, 3
For MySQL
create table tmp(x varchar(100));
insert into tmp
select 'db01' union all select '1' union all select '1e2' union all
select '1234' union all select '' union all select null union all
select '1.2e4' union all select '1.e10' union all select '0' union all
select '1.2e+4' union all select '1.e-10' union all select '1e--5' union all
select '.' union all select '.123' union all select '1.1.23' union all
select '-.123' union all select '-1.123' union all select '--1' union all
select '---1.1' union all select '+1.123' union all select '++3' union all
select '-+1.123' union all select '1 1' union all select '1e1.3' union all
select '1.234' union all select 'e4' union all select '+.123' union all
select '1-' union all select '-3e-4' union all select '+3e-4' union all
select '+3e+4' union all select '-3.2e+4' union all select '1e1e1' union all
select '-1e-1-1';
select x,
case when x not regexp('[^0-9]') then x*1 end as SimpleInt
from tmp order by 2
For Oracle
case when REGEXP_LIKE(col, '[^0-9]') then col*1 end

Related

SQL (Oracle) use two defined list in where-statement

I'm trying to create a query where I use two pre-defines lists with multiple values as filters in a where-stakement. This so I can re-use the query easily for many value-pairs en for many value-pairs.
On Stackoverflow i found:
WITH MyListOfValues(col1) AS (
select 'MyValue1' from dual union
select 'MyValue2' from dual union
select 'MyValue3' from dual
)
SELECT *
FROM DatabaseTable
WHERE Column in (
select col1
from MyListOfValues);
Howerver it fails when i do something like:
WITH MyListOfValues1(col1) AS (
select 'MyValue1' from dual union
select 'MyValue2' from dual union
select 'MyValue3' from dual
)
AND
WITH MyListOfValues2(col1) AS (
select 'MyValue1' from dual union
select 'MyValue2' from dual union
select 'MyValue3' from dual
)
SELECT *
FROM DatabaseTable
WHERE Column1 in (
select col1
from MyListOfValues1)
AND Column2 in (
select col1
from MyListOfValues2);
Does anyone has a solution?:) I'm doing this in a siting corporate enviroment I do not have rights (so far i know) to create my own tables.
Hope you can help me out! All help would be mutch appreciated:-)
You have a syntax error. The correct syntax for CTEs is:
WITH MyListOfValues1(col1) AS (
select 'MyValue1' from dual union
select 'MyValue2' from dual union
select 'MyValue3' from dual
),
MyListOfValues2(col1) AS (
select 'MyValue1' from dual union
select 'MyValue2' from dual union
select 'MyValue3' from dual
)
SELECT *
FROM DatabaseTable
WHERE Column1 in (select col1 from MyListOfValues1) AND
Column2 in (select col1 from MyListOfValues2);
I would use exits instead
WITH MyListOfValues1(col1) AS (
select 'MyValue1' from dual union
select 'MyValue2' from dual union
select 'MyValue3' from dual
),
MyListOfValues2(col1) AS (
select 'MyValue1' from dual union
select 'MyValue2' from dual union
select 'MyValue3' from dual
)
SELECT *
FROM DatabaseTable dt
WHERE EXISTS (SELECT 1 FROM MyListOfValues1 WHERE col1 = dt.Column1) AND
EXISTS (SELECT 1 FROM MyListOfValues2 WHERE col1 = dt.Column2);
Use a collection and the MEMBER OF operator
SYS.ODCIVARCHAR2LIST is a built in VARRAY you can use:
SELECT *
FROM DatabaseTable
WHERE Column1 MEMBER OF SYS.ODCIVARCHAR2LIST( 'MyValue1', 'MyValue2', 'MyValue3' )
AND Column2 MEMBER OF SYS.ODCIVARCHAR2LIST( 'MyValue1', 'MyValue2', 'MyValue3' );
Or you can define your own collection:
CREATE TYPE StringList IS TABLE OF VARCHAR2(20);
SELECT *
FROM DatabaseTable
WHERE Column1 MEMBER OF StringList( 'MyValue1', 'MyValue2', 'MyValue3' )
AND Column2 MEMBER OF StringList( 'MyValue1', 'MyValue2', 'MyValue3' );
You can even pass the collections as bind variables:
SELECT *
FROM DatabaseTable
WHERE Column1 MEMBER OF :List1
AND Column2 MEMBER OF :List2;

Why this query is not working and says Invalid Column name

SELECT ROUND(K1,2)
FROM (SELECT '5.66666' UNION ALL
SELECT '5.77777' UNION ALL
SELECT '5.88888' UNION ALL
SELECT '5.99999' UNION ALL
SELECT '6.66666' UNION ALL
SELECT '7.66666' UNION ALL
SELECT '8.66666' UNION ALL
SELECT '9.66666' UNION ALL
SELECT '9.55555' UNION ALL
SELECT '6.88888' AS K1) K
Error says Invalid Column name 'K1'
The column alias in a union [all] structure comes from the first query, not the last one. Move your alias there, and you should be OK:
SELECT ROUND(K1,2)
FROM (SELECT 5.66666 AS K1 UNION ALL -- Here!
SELECT 5.77777 UNION ALL
SELECT 5.88888 UNION ALL
SELECT 5.99999 UNION ALL
SELECT 6.66666 UNION ALL
SELECT 7.66666 UNION ALL
SELECT 8.66666 UNION ALL
SELECT 9.66666 UNION ALL
SELECT 9.55555 UNION ALL
SELECT 6.88888) K
Give column name for the first record, then it will take the same name for rest for records.
SELECT ROUND(K1,2)
FROM (SELECT '5.66666' AS K1 UNION ALL
SELECT '5.77777' UNION ALL
SELECT '5.88888' UNION ALL
SELECT '5.99999' UNION ALL
SELECT '6.66666' UNION ALL
SELECT '7.66666' UNION ALL
SELECT '8.66666' UNION ALL
SELECT '9.66666' UNION ALL
SELECT '9.55555' UNION ALL
SELECT '6.88888') K
Give alias name for first row of first column or give alias name for all rows
of first column :
SELECT ROUND(K1,2)
FROM
(
SELECT '5.66666' AS K1 UNION ALL
SELECT '5.77777' AS K1 UNION ALL
SELECT '5.88888' AS K1 UNION ALL
SELECT '5.99999' AS K1 UNION ALL
SELECT '6.66666' AS K1 UNION ALL
SELECT '7.66666' AS K1 UNION ALL
SELECT '8.66666' AS K1 UNION ALL
SELECT '9.66666' AS K1 UNION ALL
SELECT '9.55555' AS K1 UNION ALL
SELECT '6.88888' AS K1
) K

Can I have dynamic FROM Clause in SQL?

I'm currently working with my report parameter list of value that is dependent in another parameter.
I have come up with this idea, is there any possible way to for this to work?
WITH A AS (
SELECT DISTINCT columnA1 FROM Table1
UNION SELECT DISTINCT columnA2 FROM Table1
UNION SELECT DISTINCT columnA3 FROM Table1)
WITH B AS (SELECT DISTINCT columnB1 FROM Table1
UNION SELECT DISTINCT columnB2 FROM Table1
UNION SELECT DISTINCT columnB3 FROM Table1)
Select * from CASE WHEN (:PM_Parameter1 = 'A')
THEN A
ELSE B
END;
Assuming this is Oracle SQL, you can use a the EXISTS function to check for the parameter value, then combine the sets using UNION.
Try playing with this SQL:
select * from
(
select 'A' from dual
union
select 'B' from dual
)
where exists
(SELECT 'Y'
FROM dual
where 'parameter' = 'parameter'
)
union
select * from
(
select 'X' from dual
union
select 'Y' from dual
)
where exists
(SELECT 'Y'
FROM dual
where 'parameter' != 'parameter'
)
If you reverse both the conditions 'parameter' = 'parameter' and 'parameter' != 'parameter', it will return two different row sets.
I am sure this can be optimized again, hope it works out for you.

I need some SQL help trying to find what is not in a table

I need some help. I tried this and it does not work.
I selected all the data I needed and tried to say what's not in
the original file.
Could someone show me the correct way?
SELECT *
FROM acknowledgement t1
where t1.st01 = '110'
and (t1.shipment ='S640D14268424' or t1.Shipment ='S640D14268924' or
t1.Shipment ='S640D14268925' or t1.Shipment ='S646D14261190' or
t1.Shipment ='S646I14265886' or t1.Shipment ='S640D14268423' ...)
AND [shipment]
NOT IN(
SELECT [shipment] FROM acknowledgement
)
Any help would be useful.
You are looking for something like:
SELECT * FROM (
SELECT 'S640D14268424' AS Shipment
UNION SELECT 'S640D14268924'
UNION SELECT 'S640D14268925'
UNION SELECT 'S646D14261190'
UNION SELECT 'S646I14265886'
UNION SELECT 'S640D14268423'
UNION SELECT 'S646D14269951'
UNION SELECT 'S646D14269939'
UNION SELECT 'S646D14269034'
UNION SELECT 'S646D14269962'
UNION SELECT 'S646D14269953'
UNION SELECT 'S646D14271620'
UNION SELECT 'S646D14269030'
UNION SELECT 'S646D14269941'
UNION SELECT 'S646D14269251'
UNION SELECT 'S646D14273089'
UNION SELECT 'S646D14272388'
UNION SELECT 'S646D14273197'
UNION SELECT 'S646D14273399'
UNION SELECT 'S640D14273543'
UNION SELECT 'S640D14272952'
UNION SELECT 'S640D14272953'
UNION SELECT 'S640D14276996'
UNION SELECT 'S640D14277005'
UNION SELECT 'S640D14277006'
UNION SELECT 'S646D148047394'
UNION SELECT 'S640D14277004'
UNION SELECT 'S646D158049311'
UNION SELECT 'S646D158049791'
UNION SELECT 'S646D158049797'
UNION SELECT 'S646D158049806'
UNION SELECT 'S646D158049781'
UNION SELECT 'S646D158049557'
UNION SELECT 'S646D158049064'
UNION SELECT 'S646D158049561'
UNION SELECT 'S646D158049794'
UNION SELECT 'S646D158049362'
UNION SELECT 'S646D158049361'
UNION SELECT 'S646D158049792'
UNION SELECT 'S646D158049808'
UNION SELECT 'S646D158049788'
UNION SELECT 'S646D158049365'
UNION SELECT 'S646D158049800'
UNION SELECT 'S646D158049790'
UNION SELECT 'S646D158049799'
UNION SELECT 'S646D158049803'
UNION SELECT 'S646D158049784'
UNION SELECT 'S646D158049522'
UNION SELECT 'S646D158049340'
UNION SELECT 'S646D158049796'
UNION SELECT 'S646D158049687'
UNION SELECT 'S646D158049491'
UNION SELECT 'S646D158049499'
UNION SELECT 'S646D158049484'
UNION SELECT 'S646D158049486'
UNION SELECT 'S646D158049494') numbers_to_look
WHERE Shipment NOT IN
(SELECT [shipment] FROM acknowledgement WHERE shipment>'' )
Better way to do this is create a temp table to store the numbers you want to check.

Get Var() and AVG() from many columns

I'm building a query to show average and variance from many columns.
To get the average I use this:
SELECT *,
(SELECT AVG(t.c)
FROM (
SELECT peca_1 UNION ALL
SELECT peca_2 UNION ALL
SELECT peca_3 UNION ALL
SELECT peca_4 UNION ALL
SELECT peca_5 UNION ALL
SELECT peca_6 UNION ALL
SELECT peca_7 UNION ALL
SELECT peca_8 UNION ALL
SELECT peca_9 UNION ALL
SELECT peca_10
) t(c)
) as [media]
from Durabilidade
where cd_durabilidade = 1
The result is:
Now I need a new column with VAR(media) comparing each row with first row.
Any idea?
I think this is a case where cross apply is appropriate. I am assuming that you want the variance of the values as calculated by the var() function:
SELECT *, t.avgval as [media], t.varval
from Durabilidade d cross apply
(select avg(t.val) as avgval, var(t.val) as varval
from (select d.peca_1 union all
select d.peca_2 union all
select d.peca_3 union all
select d.peca_4 union all
select d.peca_5 union all
select d.peca_6 union all
select d.peca_7 union all
select d.peca_8 union all
select d.peca_9 union all
select d.peca_10
) t(val) -- t(val) to work
) t
where cd_durabilidade = 1
Something like this?
SELECT *,
VAR(media) AS [variance]
FROM
(
SELECT *,
(SELECT AVG(t.c)
FROM (
SELECT peca_1 UNION ALL
SELECT peca_2 UNION ALL
SELECT peca_3 UNION ALL
SELECT peca_4 UNION ALL
SELECT peca_5 UNION ALL
SELECT peca_6 UNION ALL
SELECT peca_7 UNION ALL
SELECT peca_8 UNION ALL
SELECT peca_9 UNION ALL
SELECT peca_10
) t(c)
) as [media]
from Durabilidade
where cd_durabilidade = 1
) x
GROUP BY
column1_from_durabilidade
,column2_from_durabilidade
--etc
,media