select query to identify numeric or alphanumeric values - sql

I have a table like below:
TN Tier
90 1
90 N3
30 2
40 3
50 A
"Tier" column may contain numeric as well as alpha-numeric values for any TN. I want to run a select query on above table so that if for any TN, there are both(numeric and alpha-numeric) values present in Tier column then it should be called as "Mix" otherwise "Numeric" or "Non-Numeric".
Desired Output :
TN Result
90 Mix
30 Numeric
40 Numeric
50 Non-Numeric
I am able to achieve it by using multiple temp tables but i want to avoid using temp tables. Any help would be appreciated!!!

You can take use advantage of ISNUMERIC() function in SQL Server.
SELECT [TN],
CASE MAX(ISNUMERIC(Tier)) + MIN(ISNUMERIC(Tier))
WHEN 2 THEN 'Numeric'
WHEN 1 THEN 'Mix'
ELSE 'Non-Numeric'
End As Result
FROM TableName
GROUP BY TN
Here's a Demo.

For MySQL, use REGEXP with a CASE expression:
SELECT
TN,
CASE WHEN SUM(CASE WHEN Tier REGEXP '[A-Z]' AND Tier REGEXP '[0-9]'
THEN 1 ELSE 0 END) > 0 THEN 'Mix'
WHEN SUM(CASE WHEN Tier REGEXP '[A-Z]'
THEN 1 ELSE 0 END) > 0 THEN 'Non-Numeric'
WHEN SUM(CASE WHEN Tier REGEXP '[0-9]'
THEN 1 ELSE 0 END) > 0 THEN 'Numeric'
ELSE 'Other' END AS Result
FROM yourTable
GROUP BY
TN;
For SQL Server, you may slightly alter the above query by using LIKE with an appropriate pattern:
SELECT
TN,
CASE WHEN SUM(CASE WHEN Tier LIKE '%[A-Z]%' AND Tier LIKE '%[0-9]%'
THEN 1 ELSE 0 END) > 0 THEN 'Mix'
WHEN SUM(CASE WHEN Tier LIKE '%[A-Z]%'
THEN 1 ELSE 0 END) > 0 THEN 'Non-Numeric'
WHEN SUM(CASE WHEN Tier LIKE '%[0-9]%'
THEN 1 ELSE 0 END) > 0 THEN 'Numeric'
ELSE 'Other' END AS Result
FROM yourTable
GROUP BY
TN;
The SQL Server answer given by #JohnWoo is tighter than this, but as you tagged with MySQL I initially answered for this database.

You dont need any big query it can be make with simple,
try this:
Select * from table
then you can check value of you column in while loop, each time you can search string having number or not number in you record.
$string = $row['Tier'];
if (preg_match('/[A-Za-z]/', $myString) )
{
echo 'String contains letters';
}
else if(preg_match('/[0-9]/', $myString))
{
echo 'String contains numbers';
}else if($string == '')
{
echo 'String contains no letter and no number';
}

I hope, you are using mysql. It is better if you can write a custom function as follows.
delimiter //
CREATE FUNCTION is_numeric(inputValue VARCHAR(50))
RETURNS INT
BEGIN
IF (inputValue REGEXP ('^[0-9]+$'))
THEN
RETURN 1;
ELSE
RETURN 0;
END IF;
END;
Example - select is_numeric(id),is_numeric(full_name) FROM tbl_user;

Related

returning the column values as a list or else 0

I had a query where i am trying to get the results of a query, the query can have multiple rows or it can be empty, i am trying if it is empty, it should return me 0 for a column i am looking which is called as sequence
My query is like this:
select CASE WHEN COUNT(1) > 0 THEN 1 ELSE 0 END AS Sequence
from dbo.mytable
it returns me the either 1 or 0, for 1 i want that column should return me values or it should combine all the rows and return me the value of that column as list like 1,2,3,4,5,6,7
This should work.
SELECT
CASE WHEN MY_COUNT > 0 THEN 1 ELSE 0 END AS SEQUENCE
FROM
(SELECT COUNT(*) AS MY_COUNT
FROM
DBO.MYTABLE);
If you want only one row in the result set, simply do:
select (case when count(*) > 0 then 1 else 0 end) as sequence
from mytable;
If you care at all about performance, the more efficient method is:
select (case when exists (select 1 from dbo.mytable) then 1 else 0
end) as sequence

Select with pattern from table in SQLite

I have a table with a column that contains this values
patern_number
0936
09154
123456
And I have a number which can be anything.
What I want is a select which returns 1 when input number start with one of pattern else return 0
example
input number result
093628987 1
0915 0
0222 0
091546666 1
So can anyone help me?
Try this:
SELECT CASE WHEN EXISTS(
SELECT 1 FROM patern_table
WHERE inputNumber Like patern_number || '%') THEN 1
ELSE 0 END As result
SQL Fiddle Demo

Display columns that contain a carriage return

I have a Students table, which contains 7 address fields.
I need to display 1 row each for student where the address fields have carriage return, if any.
It's confused after this.
The 9th column (1st column - Student ID, 2-8 column - 7 address fields) must contain the list of column names which have a carriage return ( like addr_1, addr_3, 1 for each student ID separated by a comma)
The 10th column must contain the illegal character (in this case, carriage return).
This code must be further extended to other illegal characters identified now and then and a report has to be generated.
I am unable to work on 9th and 10th columns. Can anyone help?
SELECT pty.id,
a.addr_1,
a.addr_2,
a.addr_3,
a.addr_4,
a.addr_5,
a.addr_6,
a.addr_7
FROM addr a
inner join contact cON a.idf = c.add_idf
inner join pty ON c.pty_id = pty.id
WHERE
INSTR(a.addr_1,CHR(13)) > 0 OR
INSTR(a.addr_2,CHR(13)) > 0 OR
INSTR(a.addr_3,CHR(13)) > 0 OR
INSTR(a.addr_4,CHR(13)) > 0 OR
INSTR(a.addr_5,CHR(13)) > 0 OR
INSTR(a.addr_6,CHR(13)) > 0 OR
INSTR(a.addr_7,CHR(13)) > 0;
This sounds like a homework question. So, let me give you some hints:
(1) You can generate a table using syntax, such as:
select chr(13) as badchar from dual union all
select '!' . . .
(2) You can cross join this into the table and use a very similar where clause.
(3) You can then select the bad character from the table.
(4) You'll need an aggregation.
Actually, I would be inclined to drop the requirement of one row per student and instead have one row per student/bad character. Here is an approach:
select a.id,
a.addr_1, a.addr_2, a.addr_3, a.addr_4, a.addr_5, a.addr_6, a.addr_7,
((case when INSTR(a.addr_1, b.badChar) > 0 then 'addr_1,' else '' end) ||
(case when INSTR(a.addr_2, b.badChar) > 0 then 'addr_2,' else '' end) ||
(case when INSTR(a.addr_3, b.badChar) > 0 then 'addr_3,' else '' end) ||
(case when INSTR(a.addr_4, b.badChar) > 0 then 'addr_4,' else '' end) ||
(case when INSTR(a.addr_5, b.badChar) > 0 then 'addr_5,' else '' end) ||
(case when INSTR(a.addr_6, b.badChar) > 0 then 'addr_6,' else '' end) ||
(case when INSTR(a.addr_7, b.badChar) > 0 then 'addr_7,' else '' end)
) as addrs,
b.badChar
from a cross join
(select chr(13) as badChar from dual) as b
WHERE INSTR(a.addr_1, b.badChar) > 0 OR
INSTR(a.addr_2, b.badChar) > 0 OR
INSTR(a.addr_3, b.badChar) > 0 OR
INSTR(a.addr_4, b.badChar) > 0 OR
INSTR(a.addr_5, b.badChar) > 0 OR
INSTR(a.addr_6, b.badChar) > 0 OR
INSTR(a.addr_7, b.badChar) > 0;
It leaves an extra comma at the end of the column names. This can be removed by making this a subquery and doing string manipulations at the next level.
To put all badchars on one line would require an aggregation. However, I am not clear what the 9th and 10th columns would contain in that case.
9th column would be with a case when instr(...) then 1 else 0 end || case when instr(...) then
create table tmp (vc varchar2(20), vc2 varchar2(20));
insert into tmp values ('abcd','bcda');
insert into tmp values ('bcd','bcda');
select
case when instr(vc,'a')>0 then 'col1' else null end ||
case when instr(vc2,'a')>0 then 'col2' else null end
from tmp;
As for the second problem, you can just put 'RETURN' in the 10th column. Since you are looking for only one forbidden character and get only lines which have it.
When you come up with a solution dealing with several forbidden chars, I'll update.
In similar situations I've gone for a Big Hammer and just detected non-printing control codes with a REGEXP_LIKE(col1,'[:cntrl:]'), because next someone will add a tab or something else that breaks the data.
Is it too much to ask that a check constraint be placed on the columns to prevent this from happening?

In SQL (Tsql) what's a good way to check mutually exclusive options are correct

EDIT: damien the unbeliever, my apologies, trying to be terse I omitted saying that the design of the table is not under my control; this table is a "dump" of data we receive from another vendor, and I have to convert it from their format to ours. The reason I need a query is to find out if the data is consistent with assumptions in other parts of code. The solutions proposed looking for length or exact match of the concatenated strings are better than my pair of queries for the problem I described.
I have a working pair of queries for my problem, but I wondered if there's something a bit prettier. Exactly one of taxidflag1, taxidflag2, taxidflag3 should be filled in with * in each row. So I confirm they all have two blanks and one * like this. All fields are are non nullable.
select * from acct where 2 <>
(case when taxidFlag1 <> '' then 1 else 0 end) +
(case when taxidFlag2 <> '' then 1 else 0 end) +
(case when taxidFlag3 <> '' then 1 else 0 end)
select * from acct where 1 <>
(case when taxidFlag1 = '*' then 1 else 0 end) +
(case when taxidFlag2 = '*' then 1 else 0 end) +
(case when taxidFlag3 = '*' then 1 else 0 end)
You could do this:
select * from acct where taxidFlag1 + taxidFlag2 + taxidFlag3 = '*';
This condition is only true if two are empty ('') and one is a asterisk (*).
select *
from
acct a1
where
(select count(*) from acct unpivot (foo for taxidFlag in (taxidFlag1, taxidFlag2, taxidFlag3)) as unp where unp.row_id = a1.row_id and foo = '*') <> 1
;
where row_id is your primary key field.

Can we have multiple case then statements in sql

I am trying for something which requires case within case I just wanted to make sure if we can use multiple case then?I am running this on sql teradata
The code I am trying to use is as below
AND(
case when CHARACTER_LENGTH(drug.n)=0 then 0
when CHARACTER_LENGTH(drug.n)=1 then
(case when substring(drug.n from 1,1) in (''0'',''1'',''2'',''3'',''4'',''5'',''6'',''7'',''8'',''9'') then 1 else 0 end)
when CHARACTER_LENGTH(drug.n)=2 then
(case when substring(drug.n from 1,1) in (''0'',''1'',''2'',''3'',''4'',''5'',''6'',''7'',''8'',''9'') then 1 else 0 end *
case when substring(drug.n from 2,1) in (''0'',''1'',''2'',''3'',''4'',''5'',''6'',''7'',''8'',''9'') then 1 else 0 end )
when CHARACTER_LENGTH(drug.n)=3 then
(case when substring(drug.n from 1,1) in (''0'',''1'',''2'',''3'',''4'',''5'',''6'',''7'',''8'',''9'') then 1 else 0 end *
case when substring(drug.n from 2,1) in (''0'',''1'',''2'',''3'',''4'',''5'',''6'',''7'',''8'',''9'') then 1 else 0 end *
case when substring(drug.n from 3,1) in (''0'',''1'',''2'',''3'',''4'',''5'',''6'',''7'',''8'',''9'') then 1 else 0 end )=1
If somebody has better idea you can let me know. I cannot use isnumeric function.
Yes you can use nested CASE statements. No problems with that in Teradata
Okay -
To determine whether an arbitrary length string contains only numeric characters (or does not), you can use a recurive CTE.
Please note that I don't know whether or not your RDBMS actually supports recursive CTEs, but this is a potential solution. Also, I'm not sure of the performance implications - however, it does remove the multiple CASE effect (And why isn't that an actual numeric field, anyways?).
So... For a table that looks like this:
id ch
================
1 1234567890
2 asdg
This statement returns all rows that contain only numeric characters (of any length):
WITH splitstring (id, chard, start, orig) as (
SELECT id, SUBSTRING(ch, 1, 1), 1, ch
FROM chartable
UNION ALL
SELECT id, SUBSTRING(orig, start + 1, 1), start + 1, orig
FROM splitstring
WHERE LENGTH(orig) > start)
SELECT *
FROM chartest as a
WHERE NOT EXISTS (SELECT '1'
FROM splitstring as b
WHERE a.id = b.id
AND chard NOT BETWEEN '0' AND '9')
Without some of the larger context it's somewhat difficult to know exactly what you're trying to accomplish. However, this should be adaptable for your needs.
(As a side note, DB2 for the iSeries doesn't seem to support regex either...)