4

I'm surprised this question hasn't been asked. I must be missing something very obvious here, and I'm prepared for all the down votes and the 3 second answer.

In MSSQL you're able to call GETDATE() without having to depend on a database table but in Oracle SYSDATE has to come from DUAL. Is there no way to get the current date in Oracle without having to go through DUAL?

EDIT

Clearly, this doesn't have much to do with SYSDATE but more with my incorrect usage of it. See the following WHERE clause:

WHERE (extract(YEAR from ORDER_DATE) = (case when extract(month from SYSDATE()) < 11 then extract(year from SYSDATE()) else extract(year from SYSDATE())+1 end)

The above will not work, and from the answers here it seems that adding dual in there is not recommended. What's the most optimal solution here?

jgozal
  • 1,480
  • 6
  • 22
  • 43
  • 1
    In Oracle, all queries must have a `FROM` clause. `DUAL` is used when only one row is desired. – Gordon Linoff May 23 '19 at 17:15
  • @GordonLinoff what if you want to get the year of the current date in a where clause? Do I have to select `SYSDATE` from dual within the where clause? That would seem extremely inefficient in some situations – jgozal May 23 '19 at 17:17
  • Just use `SELECT ...... FROM some_table WHERE extract( year from sysdate) = 2019`, you don't need DUAL table. – krokodilko May 23 '19 at 17:21
  • thanks @krokodilko, that's interesting. Let me be more specific here. Would adding a CASE statement in the where clause change that rule? `WHERE extract(year from order_date) = CASE WHEN extract(year from sysdate)` .... doesn't seem to work unless y do something like `CASE WHEN extract(year from (select sysdate from dual))`.... – jgozal May 23 '19 at 17:23
  • Quite simply, dual is only needed when you don't have anything else to select from. Sysdate can be used anywhere, including in your CASE statement. In your example directly above this comment, what are you setting "extract(year from sysdate)" equal to? Example that works just fine: select * from any_table where extract(year from sysdate) = 2019 – fleetmack May 23 '19 at 17:33
  • What are you trying to achieve with that code sample? – APC May 23 '19 at 17:47
  • @APC there's a more comprehensive code sample in the question which I just added. I'm trying to dynamically change the year in a where clause depending on the current date's month – jgozal May 23 '19 at 17:58
  • Piece of cake, we do that all the time for fiscal year stuff. Our fiscal year starts 10/1. So we use something like: select case when to_char(sysdate,'MM') in ('10','11','12') then to_number(to_char(sysdate,'YYYY'))+1 else to_number(to_char(sysdate,'YYYY')) end as fy from dual; .... obviously you can use this with any table, not just dual. – fleetmack May 23 '19 at 19:10

4 Answers4

1

Your question is about sysdate, but it really has nothing to do with sysdate.

In Oracle, all select queries require a from clause. The from clause has to contain something. So, once upon a time, someone at Oracle invented dual, along with its very awkward name, as a built-in table with exactly one row. Wikipedia even has an entry on this subject.

Not all databases require a from clause for the select -- SQL Server, MySQL, and Postgres, for instance, all allow select without one.

You can use a scalar expression, such as sysdate anywhere in a query where a scalar expression is allowed. You can repeat it as many times as you like, quite independent of what is in the from clause.

You can embed a scalar expression in a subquery in any database. For instance,

select (select sysdate from dual)
from dual

and:

select (select getdate())

Are both valid expressions. However, this is almost always bad practice and should almost always be avoided. (The one exception that I can think of is using a constant in a window functions ordering clause in SQL Server to prevent the overhead of sorting, such as row_number() over (order by (select null))).

Gordon Linoff
  • 1,242,037
  • 58
  • 646
  • 786
1

You can just use SYSDATEwithout any explicit reference to the DUAL table.

Something along the lines of this: INSERT INTO SOME_TABLE(some_date) VALUES (SYSDATE)

Welcome to Oracle, where everything is baffling and contrary to common sense.

Dortimer
  • 619
  • 8
  • 25
1

Is there no way to get the current date in Oracle without having to go through DUAL?

Sysdate is a pseudo-column, which we can think of as a a function which returns the current date time. So it can used like any other function. Yes, in a query projection like ...

 select sysdate from dual;

...or ...

insert into sometable (id, date_created)
values (id_seq.nextval, sysdate);

But also in a where clause. Employees hired in the last thirty days:

 select * from emp
 where hire_date > sysdate - 30

To find employees who were hired this year we could do this:

 select * from emp
 where extract(year from hire_date) = extract(year from sysdate)

...but this might perform better

 select * from emp
 where hire_date >= trunc(sysdate, 'YYYY') -- resolves to 2019-01-01
 /

And in PL/SQL:

declare
    ld date;
begin
    ld := trunc(sysdate); 
end;
APC
  • 144,005
  • 19
  • 170
  • 281
1

Avoid writing () after sysdate.

Example - using your CASE in the WHERE clause (without using DUAL):

create table T ( dt date ) ;

insert into T ( dt ) values ( sysdate ) ;


-- just write SYSDATE, not SYSDATE()
select *
from T   
where ( extract ( year from dt ) ) = ( 
  case 
    when extract( month from sysdate ) < 11 then
      extract( year from sysdate ) 
    else
      extract( year from sysdate ) + 1
  end 
) ;

-- output
DT       
---------
23-MAY-19

DBfiddle

stefan
  • 2,182
  • 2
  • 13
  • 14
  • +1 SYSDATE isn't a function so doesn't want the extra (). It's more like a variable that holds the current date/time. – saritonin May 23 '19 at 18:13
  • @saritonin As far as I am aware of: it is not just a preference thing. Try out: Oracle (eg versions 12c and 18c) SELECT SYSDATE() FROM DUAL - you'll get an ORA-00923: FROM keyword not found where expected. – stefan May 23 '19 at 18:13
  • @saritonin I've just seen your new comment. Thanks :) – stefan May 23 '19 at 18:15
  • yeah, sorry - I deleted the other comment when I realized – saritonin May 23 '19 at 18:18
  • @saritonin but `SYSDATE` is actually a function. This was the whole root of my confusion: https://www.w3resource.com/oracle/datetime-functions/oracle-sysdate-function.php – jgozal May 23 '19 at 18:23
  • 1
    @jgozal - it's probably better to consult the (original) Oracle documentation for these kind of problems. Eg https://docs.oracle.com/en/database/oracle/oracle-database/18/sqlrf/SYSDATE.html#GUID-807F8FC5-D72D-4F4D-B66D-B0FE1A8FA7D2 – stefan May 23 '19 at 18:52
  • @stefan, straight from the docs you just referenced (highlighting key words...): SYSDATE `returns` the current date and time set for the operating system on which the database server resides. The data type of the `returned value` is DATE, and the format `returned` depends on the value of the NLS_DATE_FORMAT initialization `parameter`. The `function` requires no `arguments`. In distributed SQL statements, this `function` `returns` the date and time set for the operating system of your local database. You cannot use this `function` in the condition of a CHECK constraint. – jgozal May 23 '19 at 22:13
  • Still confused by why it;s considered a function, but doesn't get used like a function. Needless to say, your solution solved my issue – jgozal May 23 '19 at 22:16
  • 1
    @jgozal - According to the PL/SQL language reference: "If the subprogram has no parameters, or specifies a default value for every parameter, you can either omit the parameter list or specify an empty parameter list." ( https://docs.oracle.com/en/database/oracle/oracle-database/18/lnpls/plsql-subprograms.html#GUID-C04B6BF9-1B19-42F9-82D8-CA137E97A024 ). I've written examples, see https://dbfiddle.uk/?rdbms=oracle_18&fiddle=53063b8f0bd98f78b1c048e7c2212e9b . Why the "language designers" have decided to disallow () when calling SYSDATE, we may find out later :) – stefan May 24 '19 at 05:40