Oracle SQL Case with Condition - sql

I have a question regarding Oracle SQL case statement.
in the where condition I would like to apply the following condition.
if salary_date is null then effective_date should be greater than 01-Jan-2016
I have the tried as
case when salary_date is null then
trunc(effective_date) >= '01-JAN-2016' else
null end
However the above resulted in
ORA-00933: SQL command not properly ended
How can I resolve this?

The problem with your code is that SQL interpreter expects to see the value after 'then' keyword, whereas you have a condition clause.
Try something like this maybe:
case when salary_date is null and trunc(effective_date) >= '01-JAN-2016'
then <value you need>
else null

You can try this without CASE statement
SELECT
..
..
WHERE ( trunc(effective_date) >= '01-JAN-2016' AND salary_date is null )
OR ( <some other condition> )

...where salary_date is not null or effective_date >= date '2016-01-01'
Since Oracle SQL does not have "IF... THEN", use basic logic to transform your boolean expression. IF a THEN b is the same thing as (NON a) OR b. This is what I did above.
DO...NOT... compare dates to strings. '01-JAN-2016' is a string, not a date. You MUST convert it to a date, for example with to_date('01-JAN-2016', 'dd-MON-yyyy').
Or, as an alternative, note how I input a "date literal" (a fixed date). If I don't need to input a time of day, I can use the expression date '2016-01-01', which is a SQL Standard (ANSI) "date literal". Then you don't need to give a date format model; it MUST ALWAYS be in the exact format yyyy-mm-dd.

Related

Case statement with date and string

I have the following error, ORA-01841
(full) year must be between -4713 and +9999 and not be 0
The error is coming from the below case statement.
Any help on what's going on and how to fix?
SQL
SELECT
CASE
WHEN NVL(uap.us_pend_dt, act_d_dt) >= TO_CHAR(TO_DATE('".PENDING_DATE_CUTOFF."','YYYY-MM-DD'),'mm/dd/yyyy')
THEN NVL(uap.us_pend_dt, act_d_dt)
ELSE CASE WHEN NVL(act_d_dt, SYSDATE) <TO_CHAR(TO_DATE('".HIRE_DATE_CUTOFF."','YYYY-MM-DD'),'mm/dd/yyyy')
THEN act_d_dt
ELSE ua_dt
END
END AS h_DT
It looks like you are trying to convert a string ".PENDING_DATE_CUTOFF." to a date. I just did the following and got an identical error:
SELECT TO_DATE('".PENDING_DATE_CUTOFF."', 'YYYY-MM-DD') FROM dual;
Is .PENDING_DATE_CUTOFF. (with periods) the name of a column in your table? If so then omit the single quote characters, e.g.:
SELECT TO_DATE(".PENDING_DATE_CUTOFF.", 'YYYY-MM-DD') FROM dual;
Of course this will give an altogether different error [ORA-00904: ".PENDING_DATE_CUTOFF.": invalid identifier] if you run as is! So I think you might want something like the following (I'm assuming the other date columns are actual dates, and the cutoff columns are VARCHAR2 columns that are storing dates in the format YYYY-MM-DD:
SELECT CASE WHEN COALESCE(uap.us_pend_dt, act_d_dt) >= TO_DATE(".PENDING_DATE_CUTOFF.", 'YYYY-MM-DD') THEN COALESCE(uap.us_pend_dt, act_d_dt)
ELSE WHEN COALESCE(act_d_dt, SYSDATE) < (TO_DATE(".HIRE_DATE_CUTOFF.", 'YYYY-MM-DD') THEN act_d_dt
ELSE act_d_dt
END AS h_dT
FROM mytable;
Note that I also got rid of the extraneous CASE statement and converted the Oracle-specific NVL() function to the ANSI-standard COALESCE() function.
EDIT: In the event that your *_dt columns are strings and not dates, best to convert them to dates using TO_DATE() before comparing - that way you're comparing dates to dates.
Hope this helps.
Presumably, your date columns are stored as dates. So, do the comparison as dates not strings:
SELECT (CASE WHEN NVL(uap.us_pend_dt, act_d_dt) >= TO_DATE('".PENDING_DATE_CUTOFF."', 'YYYY-MM-DD')
THEN NVL(uap.us_pend_dt, act_d_dt)
WHEN NVL(act_d_dt, SYSDATE) < TO_DATE('".HIRE_DATE_CUTOFF."', 'YYYY-MM-DD')
THEN act_d_dt
ELSE ua_dt
END) AS h_DT
You also don't need the extra case expressions.

Regular expression for mm/yy in Microsoft SQL Server

I am trying to execute a regular expression in SQL Server to match a MM/YY formatted VARCHAR string.
I have tried
WHERE ExpiryDate LIKE '[0-9][0-9]/[0-9][0-9]'
which allows incorrect dates like 30/18.
I also tried
WHERE ExpiryDate LIKE '0[1-9]|1[012]/[0-3][0-9]'
But SQL Server does not accept pipe separated as an OR operator.
I need the month to match 01 - 12
I can do
WHERE ExpiryDate LIKE '0[1-9]/[0-9][0-9]'
OR ExpiryDate LIKE '10/[0-9][0-9]'
OR ExpiryDate LIKE '11/[0-9][0-9]'
OR ExpiryDate LIKE '12/[0-9][0-9]'
but I would prefer it to be within the regular expression.
Thanks in advance for any help.
If 2012+, you could use try_convert() to convert the expiration string into a date. Try_Convert() will return a NULL value if the conversion fails.
Example
Declare #YourTable table (ID int, ExpiryDate varchar(25))
Insert Into #YourTable values
(1,'09/17')
,(2,'30/17')
Select *
From #YourTable
Where try_convert(date,replace(ExpiryDate,'/','/01/')) >= '2017-09-01'
-- Where try_convert(date,replace(ExpiryDate,'/','/01/')) is null
Returns
ID ExpiryDate
1 09/17
If you need to convalidate dates, you could try something like this:
SET DATEFORMAT dmy
;WITH A AS (SELECT '18/12' AS EXPDATE UNION ALL SELECT '10/17' UNION ALL SELECT 'x2/16' )
SELECT *, ISDATE('01/'+EXPDATE) AS CHK FROM A
Output:
EXPDATE CHK
18/12 0
10/17 1
x2/16 0
date LIKE '0[1-9]/[0-9][0-9]' OR
date LIKE '1[0-2]/[0-9][0-9]'
Is much shorter. But without | it is hard to make variants... Notice, that LIKE takes not regexes, but wildcards.
Don't forget, that '[1-9]/[0-9][0-9]' can also happen. And other variants, with inner spaces and so on. If you are not absolutely sure in month format used, and don't depend on high speed, use #JohnCampeletti variant.

If/then/else in SQL Query

I would like to check a date value in my SQL query. If a date is equal to a predefined date then do not print anything, ELSE print the existing date value.
How can I write it correctly in order to take the desired date value ?
I have the following query:
(SELECT (CASE
WHEN (PaymentsMade.PaymentDate = '09/09/1987') THEN ' '
ELSE PaymentsMade.PaymentDate
END)
) as dateOfPayment
When I run this query it works correctly when the date is equal to '09/09/1987' , whereas when the date is not equal to '09/09/1987' it prints '01/01/1900'.
How can I retrieve the dates values that are not equal to the predefined date '09/09/1987'?
Any advice would be appreciated.
Thanks
The CASE clause needs to return a consistently-typed value, so it is implicitly converting a space to a date (which is evaluated as 1 Jan 1900).
You have two choices:
select a null instead of a blank space.
explicitly cast the date in the else condition to a string.
Here's an (implicit) example of the former:
SELECT (CASE WHEN PaymentsMade.PaymentDate <> '09/09/1987'
THEN PaymentsMade.PaymentDate
END)
as dateOfPayment
Use NULL, not empty string
An empty string is cast to zero implicitly, which is '01/01/1900'
SELECT CAST('' AS datetime)
Using a CASE statement changes the value in that field, but doesn't change which rows are returned.
You appear to want to filter out rows, and if that is the case, use a WHERE clause...
SELECT
*
FROM
PaymentsMade
WHERE
PaymentDate <> '09/09/1987'
You could use NULLIF to replace a specific date with a NULL:
SELECT NULLIF(PaymentsMade.PaymentDate, '09/09/1987')
FROM ...
Don't just use an empty string, because it would be converted to the type of PaymentDate, which is probably a datetime, and an equivalent datetime for '' would be 1900-01-01 00:00:00.000.

SELECT dates where IN(NULL,>=SYSDATE)

Is that possible? Can one
SELECT * FROM DATES_TBL WHERE DATES_TBL.DATES IN(NULL, >=SYSDATE)
? Maybe I am formatting it incorrectly, or missing a tick?
What I would like to select are values from the date field that are NULL or greater than today's date (>=SYSDATE). Any help would be appreciated.
SQL 10g
SELECT *
FROM DATES_TBL
WHERE DATES IS NULL OR DATES >= SYSDATE
The NULL value is a special value so you must write your statement like that:
SELECT *
FROM DATES_TBL
WHERE DATES IS NULL
OR DATES >= SYSDATE
This is definitely not a valid syntax: IN queries require specific items; also, because in SQL null never equals anything, including other nulls, it does not make sense to put nulls into an IN list.
What you need instead is an OR:
SELECT * WHERE (DATES_TBL.DATES IS NULL) OR (DATES_TBL.DATES>=SYSDATE)
-- ^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^
-- | |
-- | +- This is how you compare for >=
-- +------------- This is how you check for NULL
Every time I try to use an OR clause it causes a lot of run time
In cases when OR is introduced to combine non-overlapping results (which is true in this case, because a column is either null or is greater than SYSDATE, but not both) you can use UNION ALL to potentially speed up the search:
SELECT * WHERE DATES_TBL.DATES IS NULL
UNION ALL
SELECT * WHERE DATES_TBL.DATES >= SYSDATE
You need to make sure that DATES_TBL.DATES column is indexed.
Assuming this is for Oracle, try this:
SELECT * FROM DATES_TBL WHERE (DATES_TBL.DATES is null or DATES_TBL.DATES >= sysdate)
The parenthesis make it work.

sql query condition on temporary column

I pondered on this one a little bit. Found a few question on SO but none of them addressed my problem.
What I am trying to do is compare two dates in a table, I am returning the greater of the two using a case statement
select <-- similar code but not actual code
...
case
when date1 > date2 then date1 else date2 end as lastDate
Everything fine upto this point. I get the greater date in my result. The problem is I want to apply a WHERE clause on LastDate. Since the lastDate is a temporary column, it won't be accept in WHERE clause I came up with this syntax
if #cur_date != null <---- this is parameter to my store procedure, if not null then
case when date1 > date then date1 like '2011-%' else date2 like '2011-%'
But I get an error for the misplaced 'like' keyword. I think a statement can not be returned after the 'then' keyword in case statement. How do I do this? Do I have to use temporary table for this? I want to find the best approach.
Use your same syntax in the WHERE clause:
WHERE case when date1 > date2 then date1
else date2 END
like '2011-%'
EDIT:
Sample code for Date comparison:
WHERE case when date1 > date2 then CAST(date1 as varchar)
else CAST(date2 as varchar) END
like '2011-%'