Display columns that contain a carriage return - sql

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?

Related

way to have query with case statement

I have table called Numbers in that column I have values from 0 - 10 but I like to keep value of 1-10 only change record of 0 too null
Case numbers
when 0
then ''
but I found this has changed all values and not values that have 0 is there way I can say else leave value as is?
Do you want this?
update t
set number = null
where number = 0;
Or as a select:
select t.*,
(case when number <> 0 then number end)
from t;
SELECT CASE WHEN [column] = 0 THEN NULL ELSE [column] END AS [SomeName]
FROM Numbers

how do you check for nulls in any column in an entire table in SQL

I would like to check if any of my columns in a table have any null values. I am sure there is a quicker way than how I am doing it at the moment. I just want to see if there is a NULL in ANY column however my table has a lot of columns, is there a simple and quick way?
This way I have written so far works but it takes a long time to do for every column (hence the etc etc)
select
sum(case when id is null then 1 else 0 end) as id,
sum(case when name is null then 1 else 0 end) as name,
sum(case when review_count is null then 1 else 0 end) as review_coun,
sum(case when positive_review is null then 1 else 0 end) as
positive_review,
sum(etc etc
from user
I don't know if this will work for your scenario, but it's an option. You can CAST all your columns as a string and then concatenate them together. If you concatenate a NULL value with a string, it will return NULL.
SELECT 'Y'
WHERE EXISTS( -- Check if there are any NULL rows
SELECT
CAST(c1 AS CHAR(1)) ||
CAST(c2 AS CHAR(1)) ||
...
AS MyColumns
WHERE MyColumns IS NULL
)
;

select query to identify numeric or alphanumeric values

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;

SQL : finding which clause is making my query returning no answer

My query is basic and look like this :
SELECT ID FROM Table WHERE CRIT1='a' AND CRIT2='b' AND CRIT3='c'
However it sometimes return no value. This is normal because there is no match in the table.
To help my users to find which criteria is too restrictive, I would like to find another query which tell me if it is because of clause CRIT1, CRIT2 or CRIT3 that I have no answer.
Currently, I've done it this way (using pseudo code) :
If ( SELECT ID FROM Table WHERE CRIT1='a' returns EOF )
Then WrongCriteria="CRIT1"
Elseif ( SELECT ID FROM Table WHERE CRIT1='a' AND CRIT2='b' returns EOF )
Then WrongCriteria="CRIT2"
Elseif ( SELECT ID FROM Table WHERE CRIT1='a' AND CRIT2='b' AND CRIT3='c' returns EOF )
Then WrongCriteria="CRIT3"
It works ... but there are several queries and each of them is very slow due to the poor network response time.
My question is thus : It is possible to do the above pseudo-code in one single SQL query?
You can combine three queries into one by using SUM on a conditional:
SELECT
SUM(CASE WHEN CRIT1='a' THEN 1 ELSE 0 END) as CRIT1
, SUM(CASE WHEN CRIT1='a' AND CRIT2='b' THEN 1 ELSE 0 END) as CRIT2
, SUM(CASE WHEN CRIT1='a' AND CRIT2='b' AND CRIT3='c' THEN 1 ELSE 0 END) as CRIT3
FROM MyTable
Zero in a column corresponds to the criterion being to restrictive.
Note that this is only a different implementation of your three queries, which "prioritizes" the criteria in a specific way (crit1 then crit2 then crit3). In theory, with three criteria you want to test all individual ones, plus three combinations of pairs, i.e get six counts for these conditions:
CRIT1='a'
CRIT2='b'
CRIT3='c'
CRIT1='a' && CRIT2='b'
CRIT1='a' && CRIT3='c'
CRIT2='b' && CRIT3='c'
The above six counts would give you a full picture of which criteria are too restrictive.
Yes it's possible to do this check in a single query using 'OR' operator.
I'm assuming it's only one condition which can be wrong at a time:
SELECT CASE WHEN CRIT1 <> 'a' THEN 'CRIT1'
WHEN CRIT2 <> 'b' THEN 'CRIT2'
WHEN CRIT3 <> 'c' THEN 'CRIT3' END AS WrongCriteria
FROM Table WHERE CRIT1<>'a' OR CRIT2<>'b' OR CRIT3<>'c'
To show all combinations of restrictions:
SELECT
COALESCE( 'Conditions:'
+ NULLIF(
( CASE WHEN CRIT1 <> 'a' THEN ' CRIT1' ELSE '' END )
+ ( CASE WHEN CRIT2 <> 'b' THEN ' CRIT2' ELSE '' END )
+ ( CASE WHEN CRIT3 <> 'c' THEN ' CRIT3' ELSE '' END ),
'' ),
'None' ) AS Restrictions
FROM MyTable

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.