I have two columns in my table start_date and end_date and my query inputs two values input_start_date and input_end_date.
I want the data from input_start_date to input_end_date by querying start_date and end_date.
I am able to achieve this by following query:
SELECT * FROM table-name where (
(start_date >= input_start_date and end_date <= input_end_date) or
(start_date <= input_start_date and end_date >= input_end_date) or
(start_date >= input_start_date and start_date <=input_end_date) or
(end_date >= input_start_date and end_date <= input_end_date)
);
Is there any better way of doing it ?
SELECT column-names
FROM table-name
WHERE column-name BETWEEN value1 AND value2
This one is for between one date
SELECT column-names
FROM table-name
WHERE start_date = input_start_date AND end_date = input_end_date
Related
I have a table in database with start_date, end_date and I want to fetch record from database, with date filter, as fetch those records "As on given date".
Eg:
Id start_date end_date
1 1980-01-01 1984-12-31
2 1985-01-01 2009-12-31
3 2010-01-01 2018-12-31
4 2019-01-01 null
5 1940-01-01 null
So now If I pass on date (Desired Output)
**1940-01-01**, it should return #Id=5 (number of records == 1)
**1980-01-02**, it should return #Id=1,5 (number of records == 2)
**1985-01-01**, it should return #Id=1,2,5 (number of records == 3)
**2010-01-01**, it should return #Id=1,2,3,5 (number of records == 4)
**2019-01-01**, it should return #Id=1,2,3,4,5 (number of records == 5)
**2021-01-01**, it should return #Id=1,2,3,4,5 (number of records == 5)
I tried a number of queries, but none seemed to work like
select * from table where (end_date <= '1980-01-02' or end_date is null)
select * from table where '1980-01-01 00:00:00' between start_date and coalesce(end_date, '2999-12-31')
select * from table where (end_date <= '1980-01-01 00:00:00' or end_date is null) and start_date <= '1980-01-01 00:00:00'
Any help will be appriciated.
Use the infinity timestamp literals and between for this:
select *
from "table"
where '1940-01-01' between coalesce(start_date, timestamp '-infinity')
and coalesce(end_date, timestamp 'infinity')
;
The logic that makes sense to me is:
select t.*
from t
where :date >= start_date and
(:date <= end_date or end_date is null);
However, this is not consistent with your stated results. It conforms to my reading of what you want.
For the query below, I'm trying to pull a specific date range depending on the current day of the month. If it's the 20th or less (e.g. "2/7/2020") then I want the date range for January. Otherwise, I want the date range for February. Is it possible to be done with a case statement? Or there is a better way?
SELECT
account,
start_date,
amount
FROM
table1
WHERE
CASE
WHEN (
SELECT
CAST(EXTRACT(DAY FROM sysdate) AS NUMBER)
FROM
dual
) <= 20 THEN
start_date
BETWEEN '2020-01-01' AND '2020-01-31'
ELSE start_date BETWEEN '2020-02-01' AND '2020-02-29'
END
You can do this by avoiding the case statement and using truncate the date - 20 to the month, e.g.:
SELECT account,
start_date,
amount
FROM table1
WHERE start_date >= TRUNC(SYSDATE - 20, 'mm')
AND start_date < add_months(TRUNC(dt - 20, 'mm'), 1);
If you really had to use a CASE expression (you can't use a CASE statement in SQL), you would need to do something like:
SELECT account,
start_date,
amount
FROM table1
WHERE start_date >= CASE WHEN to_char(SYSDATE, 'dd') <= '20' THEN add_months(TRUNC(SYSDATE, 'mm'), -1) ELSE TRUNC(SYSDATE, 'mm') END
AND start_date < CASE WHEN to_char(SYSDATE, 'dd') <= '20' THEN TRUNC(SYSDATE, 'mm') ELSE add_months(TRUNC(SYSDATE, 'mm'), 1) END;
N.B. if you're using a function, you don't need to wrap it in a select .. from dual, you can use it directly in the SQL statement.
I've also assumed that you want a dynamic range, e.g. if the day of the month is 20 or less, the range is for the previous month, otherwise the current month.
ETA: You would use the above two queries if there is an index on the start_date column, otherwise you could simply do:
SELECT account,
start_date,
amount
FROM table1
WHERE TRUNC(start_date, 'mm') = TRUNC(SYSDATE - 20, 'mm');
Case statements return single values. As such you should pull out the start date and you'll need two case statements.
select account, start_date, amount
from table1 where
start_date between
(case
when (select cast(extract(day from sysdate) as number) from dual) <= 20 then '2020-01-01'
else '2020-02-01'
end) and
(case
when (select cast(extract(day from sysdate) as number) from dual) <= 20 then '2020-01-31'
else '2020-02-29'
end)
One method subtracts 20 days and then gets the month boundary:
where start_date >= trunc(sysdate - interval '20' day, 'MON') and
start_date < trunc(sysdate - interval '20' day, 'MON') + interval '1' month
This approach is index (and partition) friendly -- an appropriate index on start_date can be used. It is also safe if start_date has time components.
Note: You can use sysdate without having to use a subquery.
You can use or operator with last_day function as following:
Select * from your_table
Where (
start_date <= trunc(sysdate,'mm') + 20
and start_date between trunc(sysdate,'mm') - interval '1' month and trunc(sysdate,'mm') - 1
)
Or
(
start_date > trunc(sysdate,'mm') + 20
and start_date between trunc(sysdate, 'mm') and last_day(sysdate)
)
This approach will use index on start_date, if any.
Cheers!!
select account, amount, start_date
from table1
where ( ( (select cast (extract (day from sysdate) as number) from dual) <= 20
and start_date between date '2020-01-01' and date '2020-01-31')
or ( (select cast (extract (day from sysdate) as number) from dual) > 20
and start_date between date '2020-02-01' and date '2020-02-29')
);
Using CASE expressions as BETWEEN operands:
SELECT account
, start_date
, amount
FROM table1
WHERE start_date BETWEEN CASE
WHEN extract(day from sysdate) <= 20
THEN trunc(sysdate -interval '1' month, 'month')
ELSE trunc(sysdate, 'month')
END
AND CASE
WHEN extract(day from sysdate) <= 20
THEN last_day(sysdate -interval '1' month)
ELSE last_day(sysdate)
END
This is example:
create table test (
id int,
name varchar(6),
start_date date,
end_date date
);
insert into test (id,name, start_date, end_date) values (1,'aaa', '2014-07-01', '2014-07-30');
insert into test (id,name, start_date, end_date) values (2,'bbb', '2014-07-01', '2014-08-30');
insert into test (id,name, start_date, end_date) values (3,'ccc', '2014-08-01', '2014-08-30');
insert into test (id,name, start_date, end_date) values (4,'ddd', '2014-08-16', '2014-08-30');
insert into test (id,name, start_date) values (5,'eee', '2014-07-01');
insert into test (id,name, start_date) values (6,'fff', '2014-08-16');
I need write query where result will be:
2;"bbb";"2014-07-01";"2014-08-30"
3;"ccc";"2014-08-01";"2014-08-30"
4;"ddd";"2014-08-16";"2014-08-30"
5;"eee";"2014-07-01";""
6;"fff";"2014-08-16";""
I've written this:
select * from test
where (start_date >= '2014-08-15' and (end_date <= current_Date or end_date is null)) or
(start_date <= '2014-08-15' and end_date is null) ;
But I see only ddd,eee and fff records.
Instead of the compare operators, you can actually use PostgreSQL's own detection of date (& time) overlaping. There are actually 2 constructs:
1) The SQL compatible OVERLAPS operator:
(start1, end1) OVERLAPS (start2, end2)
(start1, length1) OVERLAPS (start2, length2)
This one does not handle well an open-ended date-period, but you can use the the special infinity date for that.
select *
from test
where (date '2014-08-15', current_date) overlaps
(start_date, coalesce(end_date, date 'infinity'));
As far as I know, you can't use any index to speed up the query above.
Also:
Each time period is considered to represent the half-open interval start <= time < end, unless start and end are equal in which case it represents that single time instant.
2) Using the daterange type:
Ranges can be unbounded, and you can explicitly set how to handle range bounds (to include them or not).
select *
from test
where daterange(start_date, end_date, '[]') &&
daterange(date '2014-08-15', current_date, '[]');
Also, you can speed up this query, by applying a gist index on the daterange expression:
create index on test using gist ((daterange(start_date, end_date, '[]')));
SQLFiddle
I am guessing (intelligently) that you want any period that overlaps with 2014-08-15 to the present date. If so, this logic returns what you want:
select *
from test
where (start_date >= '2014-08-15' and (end_date <= current_Date or end_date is null)) or
(start_date <= '2014-08-15' and (end_date > '2014-08-15' or end_date is null));
Here is a SQL Fiddle.
select PERIOD_NAME
from gl_periods
where :l_date_from between start_date and end_date
and :l_date_to between start_date and end_date
This query is not working.
I need to select from date and to date between those two columns.And should display all period names between those two dates.
Help me with this query.
Try this:
select PERIOD_NAME
from gl_periods
where :l_date_from <= end_date
and :l_date_to >= start_date
If I have table with a Date column (Date field) called created_date, with values like "9/2/2010 5:25:42 PM".
I want to select all rows from a start_date to a end_date. However, the end_date may be null. In this case, I want to select all rows where created_date is greater than end_date.
Since toDate (which can be null) is a host variable, it's easier than the solutions already given (which are all wrong in that regard, btw)
select * from mytable
where created_date between v_fromdate
and nvl(v_todate, to_date('31.12.9999','dd.mm.yyyy'));
select *
from TABLE
where created_date >= '2010-09-02' and (created_date is NULL or created_date <= '2010-09-03')
Why just use a simple SQL query for that, like this one:
select xxx from table_names where created_date is null or (created_date >= to_date("02/09/2010", "dd/mm/yyyy") and created_date <= to_date("03/09/2010", "dd/mm/yyyy"));
Edit
You can define a query like the one defined by ammoQ, i.e. something like that:
select xxx from table_names where created_date is null or created_date >= start_date and created_date <= nvl(end_date, to_date("31/12/9999", "dd/mm/yyyy"));
However, as you are using PL/SQL, you can check the nullability of end_date parameter:
IF end_date IS NULL THEN
select xxx from table_names where created_date is null or created_date >= start_date;
ELSIF
select xxx from table_names where created_date is null or created_date >= start_date and created_date <= end_date;
END IF;
Note that you can remove the created_date is null condition if created_date is not a nullable column...
select * from yourtable
where created_date >= #StartDate AND created_date <=ISNULL(#EndDate,created_date)
SELECT *
FROM A_TABLE
WHERE CREATED_DATE >= &START_DATE AND
(CREATED_DATE <= &END_DATE OR
&END_DATE IS NULL)
If i took it right from your question
this should work:
SELECT *
FROM yourTable
WHERE created_date >= to_date('01.09.2010', 'dd.mm.yyyy')
AND (end_date <= to_date('02.09.2010', 'dd.mm.yyyy')
OR end_date IS NULL);