Oracle (SQL Statements) - Using CASE with WHERE CLAUSE - sql

Dear Experts,
I preparing an SQL report to display the data with Format_Check validations using CASE. I have provided the example,issues and expectation below:
Table Structure:enter image description here
SQL Statement:
SELECT
ID,PRODUCT,COMMENTS
CASE WHEN SUBSTR(COMMENTS,1,35)=REGEXP_SUBSTR (COMMENTS,'(\d)(\d)(\d)(\d)(\d)(\d)(\d)(\d)(\s)(\d)(\d)(\d)(\d)(\d)(\d)(\d)(\d)(\s)(\d)(\d)(\d)(\d)(\d)(\d)(\d)(\d)(\s)(\d)(\d)(\d)(\d)(\d)(\d)(\d)(\d)',1,1)
AND
LENGTH(TRIM(REGEXP_SUBSTR (COMMENTS, '(\S*)(\s)', 1, 2)))=8
AND
REGEXP_LIKE(TRIM(REGEXP_SUBSTR (COMMENTS, '(\S*)(\s)', 1, 1)),'(\d)(\d)(\d)(\d)(\d)(\d)(\d)(\d)')
THEN 'Correct Format'
ELSE 'Incorrect_Format'
END AS Format_Check
FROM TEST_TABLE
SQL Output:
enter image description here
SQL Output Explanation:
Checks whether COMMENTS column is 35 Character long, also checks the format numbers and spaces. SUBSTR(COMMENTS,1,35)=REGEXP_SUBSTR
(COMMENTS,'(\d)(\d)(\d)(\d)(\d)(\d)(\d)(\d)(\s)(\d)(\d)(\d)(\d)(\d)(\d)(\d)(\d)(\s)(\d)(\d)(\d)(\d)(\d)(\d)(\d)(\d)(\s)(\d)(\d)(\d)(\d)(\d)(\d)(\d)(\d)',1,1)
Checks whether the comments after first space is 8 characters long LENGTH(TRIM(REGEXP_SUBSTR (COMMENTS, '(\S*)(\s)', 1, 2)))=8
Checks the first 8 characters is digit/number. REGEXP_LIKE(TRIM(REGEXP_SUBSTR (COMMENTS, '(\S*)(\s)', 1,
1)),'(\d)(\d)(\d)(\d)(\d)(\d)(\d)(\d)')
Expectation:
I need only the 'Incorrect Format' comments to be displayed when the SQL is executed, I don't wish to see the 'Correct Format' comments. However I need your advise on whether this case be used with WHERE clause to display only incorrect format COMMENTS alone.
I referred previous queries related to WHERE and CASE, however I can't figure out on how pass my case in WHERE clause.
Thanks for your help.

If you want to display the incorrect format columns, you can wrap your query with another one:
SELECT id, product, comment, format_check
FROM (
SELECT id, product, comment, CASE WHEN .... END AS format_check
FROM test_table
)
WHERE format_check = 'Incorrect_Format';
BTW, your question is easier to answer if you show your table and data with SQL instead of an image, for instance like:
CREATE TABLE test_table (id NUMBER, product VARCHAR2(10), comments VARCHAR2(50));
INSERT INTO test_table VALUES (1,'Laptop', '00000001 01012020 02022020 03032020');
INSERT INTO test_table VALUES (1,'PC', ' 00000001 01012020 02022020 0034');
Furthermore, I believe the regular expression can be simplified. Please provide a bit more detail if you're interested...

If you do not wish to see the correct format in the result at all then you can omit the calculation of the format in select clause. Rather use it in Where clause as follows:
SELECT ID,
PRODUCT,
COMMENTS,
'Incorrect_Format' AS format_check
FROM TEST_TABLE
WHERE CASE WHEN SUBSTR(COMMENTS,1,35)=REGEXP_SUBSTR (COMMENTS,'(\d)(\d)(\d)(\d)(\d)(\d)(\d)(\d)(\s)(\d)(\d)(\d)(\d)(\d)(\d)(\d)(\d)(\s)(\d)(\d)(\d)(\d)(\d)(\d)(\d)(\d)(\s)(\d)(\d)(\d)(\d)(\d)(\d)(\d)(\d)',1,1)
AND
LENGTH(TRIM(REGEXP_SUBSTR (COMMENTS, '(\S*)(\s)', 1, 2)))=8
AND
REGEXP_LIKE(TRIM(REGEXP_SUBSTR (COMMENTS, '(\S*)(\s)', 1, 1)),'(\d)(\d)(\d)(\d)(\d)(\d)(\d)(\d)')
THEN 'Correct Format'
ELSE 'Incorrect_Format'
END AS = 'Incorrect_Format'

Related

get sub string in between mix symbols

I want to get sub string my output should look like gmail,outlook,Skype.
my string values are
'abc#gmail.com'
'cde.nitish#yahoo.com'
'xyz.vijay#sarvang.com.com'
somthing like this as you can see its having variable length with mix symbol '.' and '#'
string values store in table form as a column name Mail_ID and Table name is tbl_Data
i am using sql server 2012
i use chart index for getting sub string
select SUBSTRING(Mail_ID, CHARINDEX('#',MAil_ID)+1, (CHARINDEX('.',MAil_ID) - (CHARINDEX('#', Mail_ID)+1)))
from tbl_data
And i want my output like:
'gmail'
'yahoo'
'sarvang'
Please help me i am newbies in sql server
This is my solution. I first get the position of the '#', and then get the position of the '.' in the string prior to it (the '#'). Then I can use those results to get the appropriate substring:
SELECT V.YourString,
SUBSTRING(V.YourString,D.I,A.I - D.I) AS StringPart
FROM (VALUES('abc#gmail.com'),
('cde.nitish#yahoo.com'),
('xyz.vijay#sarvang.com.com'))V(YourString)
CROSS APPLY(VALUES(CHARINDEX('#',V.YourString)))A(I) --Get position of # to not repeat logic
CROSS APPLY(VALUES(CHARINDEX('.',LEFT(V.YourString,A.I))+1))D(I) --Get position of . to not repeat logic
Note for value of 'abc.def.steve#... it would return 'def.steve'; however, we don't have such an example so I don't know what the correct return value would be.
I'm posting this as a new answer, a the OP moved the goal posts from the original answer. My initial answer was based on their original question, not their "new" one, and it seems silly to remove an answer that was correct at the time:
SELECT V.YourString,
SUBSTRING(V.YourString,A.I, D.I - A.I) AS StringPart
FROM (VALUES('abc#gmail.com'),
('cde.nitish#yahoo.com'),
('xyz.vijay#sarvang.com.com'))V(YourString)
CROSS APPLY(VALUES(CHARINDEX('#',V.YourString)+1))A(I)
CROSS APPLY(VALUES(CHARINDEX('.',V.YourString,A.I)))D(I);
This answers the original version of the question.
This may be simplest with a case expression to detect if there is a period before the '#':
select (case when email like '%.%#%'
then stuff(left(email, charindex('#', email) - 1), 1, charindex('.', email), '')
else left(email, charindex('#', email) - 1)
end)
from (values ('abc#gmail.com'), ('cde.nitish#yahoo.com'), ('xyz.vijay#sarvang.com.com')) v(email)
I create a temp table with your data and write below query its worked
CREATE TABLE #T
(
DATA NVARCHAR(50)
)
INSERT INTO #T
VALUES('abc#gmail.com'),
('cde.nitish#yahoo.com'),
('xyz.vijay#sarvang.com.com')
SELECT *,LEFT(RIGHT(DATA,LEN(DATA)-CHARINDEX('#',DATA,1)),CHARINDEX('.',RIGHT(DATA,LEN(DATA)-CHARINDEX('#',DATA,1)),1)-1)
FROM #t
AND its a output of my T-SQL
abc#gmail.com gmail
cde.nitish#yahoo.com yahoo
xyz.vijay#sarvang.com.com sarvang

How to test a condition in a sql case statement on numbers

I would like to substitute all the values that are greater or equal to 10 with an empty string with a SQL CASE statement on my Microsoft SQL Server 2017. However, I am getting an error that reads:
Msg 102, Level 15, State 1, Line 13
Incorrect syntax near '>'.
Though there are some questions similar to my question, I can not find an answer that is specifically answering my question. For example this question here how to use > = condition in sql case statement?. I have also tried a dynamic query with a temporal table and this did not help.
Here is my code with the table definition and the test data as well as the actual query that I am running.
--table definition with two columns
declare #table table
(
person nvarchar(20),
digit decimal(10,2)
)
--insert test data with two records
insert into #table
select 'titimo', 9.51
union
select 'neriwo', 12.25
--the requirement is to not show the digit value if it is greater or equal to 10, but rather display an empty field.
--so, this is my select statement to meet this requirement that is failing
--with error message 'Incorrect syntax near >'
select
person,
case digit
when digit >= 10 then ''
else digit
end 'digit'
from #table
From my select statement above, I am expecting this output:
person digit
------ -----
titimo 9.51
neriwo
However, the output is not being generated because of the error message that I am experiencing.
You had a syntax error in your case. More over you cannot mix datatypes so you need to cast digit to varchar or change '' i.e. to null.
select
person,
case
when digit >= 10 then ''
else cast(digit as varchar(20))
end 'digit'
from #table
Your case is not formatted correctly - here's one option -
(also, you can't select text and numbers in the same column - so I casted your number to text... tweak to fit your needs)
select
person,
case when digit >=10 then ''
else CONVERT(VARCHAR(10), digit)
end 'digit'
from #table

Is using sequence in db2 statements possible?

I am trying to execute following statement in DB2.
This works well.
SELECT NEXT VALUE FOR SCPYMNT.REM_QUERY_NO_SEQ
FROM sysibm.sysdummy1
However, this throws a database error.
SELECT (
CASE WHEN PYMT_SYS = 1 THEN NEXT VALUE FOR SCPYMNT.REM_QUERY_NO_SEQ
WHEN PYMT_SYS = 2 THEN 'dummy'
else 'dummy'
END )
FROM sysibm.sysdummy1
So Db2 gives the error below.
Category Timestamp Message
Statusbar 18.04.2016 11:47:39 DB2 Database Error: ERROR [428F9] [IBM][DB2] SQL0348N "NEXT VALUE FOR SCPYMNT.REM_QUERY_NO_SEQ" cannot be specified in this context. SQLSTATE=428F9
It seems to me there is not a syntax error.Does Db2 not let such queries that consists of case conditions and sequence?
#MichaelTiefenbacher,I put select examples as a demonstration.(What I am really trying to achieve is something like below.
SELECT NAME, QUERYNO
FROM FINAL TABLE (INSERT INTO EMPSAMP (NAME, SALARY, QUERYNO)
VALUES('Mary Smith', 35000.00,
CASE WHEN PYMT_SYS = 1 THEN NEXT VALUE FOR REM_SEQ
CASE WHEN PYMT_SYS = 2 NEXT VALUE FOR EFT_SEQ
));
I think question is more clearer now.
Sequences can be used to generate unique keys or numbers when inserting data into tables.
They are not used to generate unique numbers when selecting data.
For that you could either retrieve the field from the table where you used the sequence at insert time or you can use row_number() in the SELECT.
It also would be helpful to tell a little more what you want to achieve.
I found out that the answer is "No" according to IBM documentation.
NEXT VALUE expressions cannot be specified in the following contexts:
CASE expression
Here is the link
Insert from a union of selects:
SELECT NAME, QUERYNO
FROM FINAL TABLE
(
INSERT INTO EMPSAMP
SELECT
'Mary Smith', 35000.00, NEXT VALUE FOR REM_SEQ
FROM SYSIBM.SYSDUMMY1
WHERE PYMT_SYS = 1
UNION ALL
'Mary Smith', 35000.00, NEXT VALUE FOR EFT_SEQ
FROM SYSIBM.SYSDUMMY1
WHERE PYMT_SYS = 2
)

Converting SQL varchar column values to $ format i.e. thousand separation

I have a varchar(256) column AttributeVal with all different type of text values.
I need to find out all $ values like $5000, $2000 etc & add thousand separator to them (only to these values, but not to the other text values present in that column).
Thus the updated values should look like $5,000 & $2,000.
If I am using following query, then it will end up converting all values & I need to concatenate $ manually :(
replace(convert(varchar, convert(Money, AttributeVal), 1), '.00', '')
NB : I know that these kind of formatting should be taken care in the application end, but our customer is adamant to have these customization to be stored in DB only.
I don't think you can do a replace statement based on a regular expression like that exactly. See this stackoverflow post asking the same question.
You may want to reinforce to your client that formatted data should not be stored in a database. That money value should probably be stored in a DECIMAL(13, 4) or something similar instead of a VARCHAR field mixed with other data as well.
Your question is a great example of why you don't want to do this. It makes simple things very difficult.
Try this
SELECT '$'+ PARSENAME( Convert(varchar,Convert(money,convert(Money, 100000)),1),2)
Output: $100,000
Hope this help!
try with this, this will take care of thousand separator :-)
'$'+convert(varchar(50), CAST(amount as money), -1) amount
Sample
;with cte (amount)
as
(
select 5000 union all
select 123254578.00 union all
select 99966.00 union all
select 0.00 union all
select 6275.00 union all
select 18964.00 union all
select 1383.36 union all
select 26622.36
)
select '$'+convert(varchar(50), CAST(amount as money), -1) amount
from cte
Here is my take on the problem:
select coalesce(cast(try_convert(money, value) as varchar(50)), value) converted
from (
values ('50')
, ('5000')
, ('3000.01')
, ('text')
) samples(value)
and the output:
converted
--------------------------------------------------
50.00
5000.00
3000.01
text
(4 row(s) affected)

SQL strip text and convert to integer

In my database (SQL 2005) I have a field which holds a comment but in the comment I have an id and I would like to strip out just the id, and IF possible convert it to an int:
activation successful of id 1010101
The line above is the exact structure of the data in the db field.
And no I don't want to do this in the code of the application, I actually don't want to touch it, just in case you were wondering ;-)
This should do the trick:
SELECT SUBSTRING(column, PATINDEX('%[0-9]%', column), 999)
FROM table
Based on your sample data, this that there is only one occurence of an integer in the string and that it is at the end.
I don't have a means to test it at the moment, but:
select convert(int, substring(fieldName, len('activation successful of id '), len(fieldName) - len('activation successful of id '))) from tableName
Would you be open to writing a bit of code? One option, create a CLR User Defined function, then use Regex. You can find more details here. This will handle complex strings.
If your above line is always formatted as 'activation successful of id #######', with your number at the end of the field, then:
declare #myColumn varchar(100)
set #myColumn = 'activation successful of id 1010102'
SELECT
#myColumn as [OriginalColumn]
, CONVERT(int, REVERSE(LEFT(REVERSE(#myColumn), CHARINDEX(' ', REVERSE(#myColumn))))) as [DesiredColumn]
Will give you:
OriginalColumn DesiredColumn
---------------------------------------- -------------
activation successful of id 1010102 1010102
(1 row(s) affected)
select cast(right(column_name,charindex(' ',reverse(column_name))) as int)
CAST(REVERSE(LEFT(REVERSE(#Test),CHARINDEX(' ',REVERSE(#Test))-1)) AS INTEGER)
-- Test table, you will probably use some query
DECLARE #testTable TABLE(comment VARCHAR(255))
INSERT INTO #testTable(comment)
VALUES ('activation successful of id 1010101')
-- Use Charindex to find "id " then isolate the numeric part
-- Finally check to make sure the number is numeric before converting
SELECT CASE WHEN ISNUMERIC(JUSTNUMBER)=1 THEN CAST(JUSTNUMBER AS INTEGER) ELSE -1 END
FROM (
select right(comment, len(comment) - charindex('id ', comment)-2) as justnumber
from #testtable) TT
I would also add that this approach is more set based and hence more efficient for a bunch of data values. But it is super easy to do it just for one value as a variable. Instead of using the column comment you can use a variable like #chvComment.
If the comment string is EXACTLY like that you can use replace.
select replace(comment_col, 'activation successful of id ', '') as id from ....
It almost certainly won't be though - what about unsuccessful Activations?
You might end up with nested replace statements
select replace(replace(comment_col, 'activation not successful of id ', ''), 'activation successful of id ', '') as id from ....
[sorry can't tell from this edit screen if that's entirely valid sql]
That starts to get messy; you might consider creating a function and putting the replace statements in that.
If this is a one off job, it won't really matter. You could also use a regex, but that's quite slow (and in any case mean you now have 2 problems).