Oracle: SELECT where date is less if not equals null - sql

I have a table of records, and one column holds the value when the records turns in-active.
Most of the records are still open, and therefore do not hold any value in the end_date column.
I want to select all of those records, which are still active. One way to achieve this (from the top of my head):
select *
from table t
where nvl(t.end_date, to_date('2099-DEC-31', 'MM-DD-yyyy')) > sysdate
But it doesn't feel right. Is there a better way to achieve what I want?
EDIT: BTW, the table isn't huge, and isn't going to grow :)

select *
from table t
where nvl(t.end_date, to_date('2099-DEC-31', 'MM-DD-yyyy')) > sysdate
won't use a "normal", non function based index, so it may hurt performance.
You could query it like
select *
from table t
where t.end_date > sysdate OR t.end_date is null
instead

Related

Dynamic start date from specific column in a table (sysdate)

I am pretty new in this field, trying to learn slowly so please be patient with me :)
My database contains a table called t_usage_interval. In this table there is a column name ID_Interval. Each month a new random 10 digit number is created in this column.
This is the query I am using
I would like to find out if there is a way to pull the latest interval by using column name DT_START with SYSDATE option? I guess it would be a dynamic query search from a sysdate to display the latest ID_Interval?
Thank you,
A
This is how I understood the question.
A straightforward query returns row(s) whose dt_start is the first in that table that is lower or equal to sysdate (you might also use trunc(sysdate), if you don't care about time component). Drawback of this query is that it scans t_usage_Interval table twice.
select *
from t_usage_interval a
where a.dt_start = (select max(b.dt_start)
from t_usage_interval b
where b.dt_start <= sysdate
);
Somewhat less intuitive option is to "rank" rows (whose dt_start is lower than sysdate) by dt_start, and then return row(s) that rank the "highest". This option scans the table only once, so it should perform better.
with temp as
(select a.*,
rank() over (order by a.dt_start desc) rn
from t_usage_interval a
where a.dt_start <= sysdate
)
select t.*
from temp t
where t.rn = 1;

SQL - find a table row with the highest number being less than a specified number

How can I efficiently find 1 table row that has the highest number in a column that is less than a specified (query) value?
UPDATE: based on the answer of #Gordon Linoff, then finding 1 table row should be the statement below? Is this the most efficient way?
select * from table1 where colname1 in
( select max( colname1) from table1 where colname1 < 528188000 )
#Eric - mostly I am not lazy, at this late I hour maybe I was a bit lazy for a second ;-)
Your approach is good and efficient. Especially, if there exists an index on table1(colname1). It should be =, though, instead of IN, because your subquery cannot return multiple rows.
select * from table1 where colname1 =
( select max(colname1) from table1 where colname1 < 528188000 )
You say that you are looking for one row. So you consider it guaranteed that colname1 values are unique in the table (maybe because there exists a unique constraint on that column). If so, it may be more efficient to tell the DBMS that you are looking for exactly one row. In standard SQL:
select *
from table1
where colname1 < 528188000
order by colname1 desc
fetch first row only;
Your DBMS may use another syntax. In SQL Server it's TOP(1); in MySQL it's LIMIT 1.
If I interpret "database" as table, then in standard SQL, you can do:
select max(col)
from t
where col < #value

PostgreSQL limiting results by year

i have a working PostgreSQL query, column "code" is common in both tables and table test.a has date column and i want to limit search results on year, date format is like ( 2010-08-25 )
SELECT *
FROM test.a
WHERE form IN ('xyz')
AND code IN (
SELECT code
FROM test.city)
any help is appreciated
To return rows with date_col values in the year 2010:
SELECT *
FROM test.a
WHERE form = 'xyz'
AND EXISTS (
SELECT 1
FROM test.city
WHERE code = a.code
)
AND date_col >= '2010-01-01'
AND date_col < '2011-01-01';
This way, the query can use an index on date_col (or, ideally on (form, date_col) or (form, code, date_col) for this particular query). And the filter works correctly for data type date and timestamp alike (you did not disclose data types, the "date format" is irrelevant).
If performance is of any concern, do not use an expression like EXTRACT(YEAR FROM dateColumn) = 2010. While that seems clean and simple to the human eye it kills performance in a relational DB. The left-hand expression has to be evaluated for every row of the table before the filter can be tested. What's more, simple indexes cannot be used. (Only an expression index on (EXTRACT(YEAR FROM dateColumn)) would qualify.) Not important for small tables, crucial for big tables.
EXISTS can be faster than IN, except for simple cases where the query plan ends up being the same. The opposite NOT IN can be a trap if NULL values are involved, though:
Select rows which are not present in other table
If by "limit" you mean "filter", then I can give you an option
SELECT
*
FROM
test_a
WHERE
form IN ('xyz')
AND code IN (
SELECT code
FROM test_city
)
AND EXTRACT(YEAR FROM dateColumn) = 2010;
db-fiddle for you to run and play with it: https://www.db-fiddle.com/f/5ELU6xinJrXiQJ6u6VH5/6

Will the partition be hit in an inner Union?

I have the followning SQL statement:
SELECT *
FROM (
SELECT eu_dupcheck AS dupcheck
, eu_date AS threshold
FROM WF_EU_EVENT_UNPROCESSED
WHERE eu_dupcheck IS NOT NULL
UNION
SELECT he_dupcheck AS dupcheck
, he_date AS threshold
FROM WF_HE_HISTORY_EVENT
WHERE he_dupcheck IS NOT NULL
)
WHERE threshold > sysdate - 30
The second table is partitioned by date but the first isn't. I need to know if the partition of the second table will be hit in this query, or will it do a full table scan?
I would be surprised if Oracle were smart enough to avoid a full table scan. Remember that UNION processes the data by removing duplicates. So, Oracle would have to recognize that:
The where clause is appropriate for the partitioning (this is actually easy).
That partitioning does not affect the duplicate removal (this is a bit harder, but true because the date is in the select).
Oracle has a smart optimizer, so perhaps it can recognize this situation (and it would probably avoid the full table scan for a UNION ALL). However, you are safer by moving the condition to the subqueries:
SELECT *
FROM ((SELECT eu_dupcheck AS dupcheck, eu_date AS threshold
FROM WF_EU_EVENT_UNPROCESSED
WHERE eu_dupcheck IS NOT NULL AND eu_date > sysdate - 30
) UNION
(SELECT he_dupcheck AS dupcheck, he_date AS threshold
FROM WF_HE_HISTORY_EVENT
WHERE he_dupcheck IS NOT NULL AND he_date > sysdate - 30
)
) eh;

Aggregate functions in WHERE clause in SQLite

Simply put, I have a table with, among other things, a column for timestamps. I want to get the row with the most recent (i.e. greatest value) timestamp. Currently I'm doing this:
SELECT * FROM table ORDER BY timestamp DESC LIMIT 1
But I'd much rather do something like this:
SELECT * FROM table WHERE timestamp=max(timestamp)
However, SQLite rejects this query:
SQL error: misuse of aggregate function max()
The documentation confirms this behavior (bottom of page):
Aggregate functions may only be used in a SELECT statement.
My question is: is it possible to write a query to get the row with the greatest timestamp without ordering the select and limiting the number of returned rows to 1? This seems like it should be possible, but I guess my SQL-fu isn't up to snuff.
SELECT * from foo where timestamp = (select max(timestamp) from foo)
or, if SQLite insists on treating subselects as sets,
SELECT * from foo where timestamp in (select max(timestamp) from foo)
There are many ways to skin a cat.
If you have an Identity Column that has an auto-increment functionality, a faster query would result if you return the last record by ID, due to the indexing of the column, unless of course you wish to put an index on the timestamp column.
SELECT * FROM TABLE ORDER BY ID DESC LIMIT 1
I think I've answered this question 5 times in the past week now, but I'm too tired to find a link to one of those right now, so here it is again...
SELECT
*
FROM
table T1
LEFT OUTER JOIN table T2 ON
T2.timestamp > T1.timestamp
WHERE
T2.timestamp IS NULL
You're basically looking for the row where no other row matches that is later than it.
NOTE: As pointed out in the comments, this method will not perform as well in this kind of situation. It will usually work better (for SQL Server at least) in situations where you want the last row for each customer (as an example).
you can simply do
SELECT *, max(timestamp) FROM table
Edit:
As aggregate function can't be used like this so it gives error. I guess what SquareCog had suggested was the best thing to do
SELECT * FROM table WHERE timestamp = (select max(timestamp) from table)