Understanding a specific WHERE clause in Oracle - oracle

I saw this as part of an Oracle SQL code
where employer.eab_yr || employer.eab_no >= 20173
and employer.eab_yr || employer.eab_no <= 20202
Can anyone explain to me what this part of the code is doing?
It appears it's fetching values from the employer table where eab_yr is between the 3rd month of 2017 and the second month of 2020. Is that correct?

|| is the string concatenation operator, >= is the greater than or equal operator and <= is the less than or equal operator.
So it matches all rows where the string concatenation of the columns eab_yr and eab_no of employer is numerically greater than or equal to 20173 and numerically less than or equal to 20202.
That's all there is. What that means semantically cannot be answered without knowing the semantics of the relation(s (there might be more than one, we cannot tell as there was no FROM clause given)) and the attributes. You didn't disclose those.

Assuming the code is concatenating year and month and trying to find a range then the code does not work as you would expect.
If you put the range from September 2017 to December 2017 then you will get the query:
where employer.eab_yr || employer.eab_no >= 20179
and employer.eab_yr || employer.eab_no <= 201712
Now, 20201 is greater than the number 20179 and is less than the number 201712 so you would find that January 2020 is returned (and so would many other unexpected months).
If you want to fix it then use a 2-digit month:
where employer.eab_yr || LPAD( employer.eab_no, 2, '0' ) BETWEEN 201709 AND 201712
or use date literals:
where TO_DATE( employer.eab_yr || '-' || employer.eab_no, 'YYYY-MM' )
BETWEEN DATE '2017-09-01' AND DATE '2017-12-01'
or, even better, fix your table so that you have a single DATE column rather than individual year and month columns.
db<>fiddle here

Related

Single Month Digit Date Format issue in Oracle

Am getting the below issue when am using 'mon-d-yyyy' to convert date to char, as i need a single day digit for values from 1 to 9 days in a month.
When i use the 'mon-d-yyyy' format, am losing out on 5 days and getting a wrong date. Any help on this would be great.
select to_char(sysdate-22,'mon-d-yyyy') from dual;--aug-2-2017
select to_char(sysdate-22,'mon-dd-yyyy') from dual;--aug-07-2017
select sysdate-22 from dual;--07-AUG-17 11.06.43
In Oracle date formats, d gets the day of week. The 2 in your output means monday, not august the 2nd.
Try using Fill Mode as Format Model Modifier
select to_char(sysdate-22,'mon-fmdd-yyyy') from dual;
One option might be to piece together the date output you want:
SELECT
TO_CHAR(sysdate-22, 'mon-') ||
TRIM(LEADING '0' FROM TO_CHAR(sysdate-22, 'dd-')) ||
TO_CHAR(sysdate-22, 'yyyy')
FROM dual;
The middle term involving TRIM strips off the leading zeroes, if present, from the date.
Output:
Demo here:
Rextester
SQL>SELECT TO_CHAR(TO_DATE('29-AUG-2017','DD-MON-YYYY') - 22,'"WEEKDAY :"D, MON-FMDD-YYYY') "Before22Days" FROM DUAL;
D- Gives you a numeric weekday(2nd weekday in a week) on AUG-07-2017.
DD-Gives a Numeric Month Day i.e,07th
FMDD-Gives 7th
Before22Days
----------------------
WEEKDAY :2, AUG-7-2017

How can I use an expression in my where clause to return a dynamic date range for my query

I am working in BIDS 2008r2 on a SSRS report that pulls data from an Oracle database.
I have a where clause that uses a hard date range, I want to change it to an expression that will dynamically change as time progresses.
This is the where clause that currently works to return the 1st day of the previous month to the last day of the previous month. ie I am looking for all data from the previous month
WHERE CHRGDTTM BETWEEN {ts '2015-12-01 00:00:00'} AND {ts '2015-12-31 23:59:00'}
I have written an expression that returns the beginning of last month:
DateAdd(DateInterval.Month, -1, DateSerial(Year(Date.Now), Month(Date.Now), 1))
and one that returns the end of last month:
DateAdd(DateInterval.Minute, -1, DateSerial(Year(Date.Now), Month(Date.Now), 1))
How do I get those into my where clause?
Thank you.
If you want to do this entirely within the Oracle where clause you can do:
WHERE CHRGDTTM >= ADD_MONTHS(TRUNC(sysdate, 'MM'), -1)
AND CHRGDTTM < TRUNC(sysdate, 'MM')
The TRUNC(date) function truncates the supplied date - the system date in this case; by default it removes the time part so gives you midnight this morning, but this modified that behaviour with the MM format model, and gives you midnight on the first of the current month. So today TRUNC(SYSDATE, 'MM') gives you 2016-01-26 00:00:00. You can use that as it is for the upper end of your date range.
The ADD_MONTHS() function, well, adds a number of months, -1 here to give you 2015-12-01 00:00:00 instead. Put together that gives you everything from 2015-12-01 00:00:00 up to, but no including, 2016-01-01 00:00:00, which is equivalent to your BETWEEN range.
You could also use an interval calculation to get the start of the previous month:
WHERE CHRGDTTM >= TRUNC(sysdate, 'MM') - INTERVAL '1' MONTH
AND CHRGDTTM < TRUNC(sysdate, 'MM')
which has the same effect, and is safe as you're always going to end up with a valid date from the calculation; dates at the ends of months can be more problematic.
You can read more about datetime/interval arithmetic in the documentation.
As an alternative, you can create two parameters of type Date/Time and set the Default Values for the parameters with the expressions you've developed. Then in the query it just becomes WHERE CHRGDTTM BETWEEN :StartDate AND :EndDate. If the user needn't worry about this, set the visibility to Hidden for both.

Contatenating two date values into one column

Should be a pretty simple question. I have two fields - one a year field and the other a month field. The month field is an integer and if there is only one digit such as 6 for June there is no leading zero. I want to concatenate the two fields together to get 201406 not 20146 if I concatenate them together now. I tried
year||to_char(month,'09') but the field is being displayed as 2014 06 with a space in-between the year and month. Is there a way to do this without a space?
If your output contains a space, then either your year or your month column contains a space. To get rid of these, you can use TRIM:
with v_data(year, month) as (
select '2015 ', ' 1' from dual union all
select ' 2014 ', ' 12 ' from dual union all
select '2014', '3' from dual
)
select trim(year) || lpad(trim(month), 2, '0')
from v_data
(this assumes that you really have two string columns - if you indeed have two date columns, please add example input to your question)
UPDATE
If you want to use to_char() instead, you should use the FM format modifier to get rid of the space:
select trim(year) || trim(to_char(month, 'FM09'))
from v_data
The issue is that, by default, to_char leaves a space in front of a positive formatted number, so that they line up well with negative numbers. To prevent this, use to_char(month,'fm09').

How to remove leading zeroes from day and month values in Oracle, when parsing to string using to_char function?

I want to retrieve a date without the leading zeroes in front of the day and month values in a select statement. If I execute the following query
select to_char(sysdate, 'dd.mm.yyyy') from dual;
I will get 21.03.2014 as a result. Moreover, if today was, for example, 7th of March, 2014, I would get 07.03.2014. How can I get rid of these leading zeroes?
select to_char(sysdate,'DD.MM.YY') -- Without Fill Mode
, to_char(sysdate-20,'fmDD.fmMM.YY') -- With Fill Mode, 20 days ago
from dual;
Returns
21.03.14 | 1.3.14
FM Fill mode.
In a datetime format element of a TO_CHAR function, this modifier suppresses blanks in subsequent character elements (such as MONTH) and suppresses leading zeroes for subsequent number elements (such as MI) in a date format model. Without FM, the result of a character element is always right padded with blanks to a fixed length, and leading zeroes are always returned for a number element. With FM, which suppresses blank padding, the length of the return value may vary.
Try this:
select to_char(to_date('20-oct-2000'),'fmmm/dd/fmrr') from dual
The above query will remove the leading zeroes from day and month values in Oracle.
This is quite far from being elegant but it works:
select to_number(to_char(sysdate,'dd')) || '.' || to_number(to_char(sysdate,'mm')) || '.' || to_number(to_char(sysdate,'yyyy')) from dual
Basically, you would convert to number each part of the date

using date function to query

I have the following table
Alarm (AlarmID INT, InstalledDate Date)
Given that the alarm need to be replace every 5 years, how do i display all the alarms that is due for replacement in the next 6 months?
I tried the following and there was no result:
SELECT AlarmID
FROM Alarm
WHERE Add_months(InstalledDate, 60)
BETWEEN SYSDATE AND Add_months(SYSDATE, 6);
"I tried the following and there was no result:"
The query you propose looks correct, so perhaps you don't have any ALARMS which are five years old?
"it seems like there is a difference using BETWEEN SYSDATE AND
Add_months(SYSDATE, 6) compare to BETWEEN Add_months(SYSDATE, 6) AND
SYSDATE;"
The BETWEEN operator demands that we pass the two values in a specific order, lower bound then upper bound. So this filter is true:
where date '2012-03-01' between date '2012-01-01' and date '2012-06-01'
whereas this is false:
where date '2012-03-01' between date '2012-06-01' and date '2012-01-01'
Perhaps this seems unfair, but the Oracle documentation makes it clearer by translating the BETWEEN operator into lt and gt statements:
where date '2012-03-01' >= date '2012-01-01'
and date '2012-03-01' <= date '2012-06-01'
If you swap the values of the second and third expressions you'll see why the reversed order returns false.

Resources