Adding today's date to Oracle query results when using wildcard * - oracle

this might be a lack of very basic knowledge, but I just can't figure it out. Searching for the answer and trial and error haven't helped much.
Returning all recordsets from a table (SELECT * FROM X) --> no problem.
Returning today's date (SELECT TO_CHAR(SYSDATE, 'DD-MM-YYYY') FROM DUAL) --> no problem.
Returning all recordsets from the same table as well as today's date --> no luck. I have tried subselects, union, joins, with-statements, ... it's driving me nuts.
When I name the columns I want returned (SELECT Columname1, Columnname2, to_char(sysdate....)) it works. This problems seems to only occur when using wildcards.
How do I get Oracle to return "all columns", today's date"?
Thanks!

You have to prefix the wildcard with the table name (or alias, if you've used one):
SELECT X.*, TO_CHAR(SYSDATE, 'DD-MM-YYYY') AS TODAYS_DATE FROM X
Using the wildcard is generally not considered a good idea, as you have no control over the order the columns are listed (if the table was built differently in different environments) and anyone consuming this output may be thrown if the table definition changes in the future, e.g. by adding another column. It's better to list all the columns individually.

Related

Query not filtering with date in Oracle

There are records in table for particular date. But when I query with that value, I am unable to filter the records.
select * from TBL_IPCOLO_BILLING_MST
where LAST_UPDATED_DATE = '03-09-21';
The dates are in dd-mm-yy format.
To the answer by Valeriia Sharak, I would just add a few things since your question is tagged Oracle. I was going to add this as a comment to her answer, but it's too long.
First, it is bad practice to compare dates to strings. Your query, for example, would not even execute for me -- it would end with ORA-01843: not a valid month. That is because Oracle must do an implicit type conversion to convert your string "03-09-21" to a date and it uses the current NLS_DATE_FORMAT setting to do that (which in my system happens to be DD-MON-YYYY).
Second, as was pointed out, your comparison is probably not matching rows due LAST_UPDATED_DATE having hours, minutes, and seconds. But a more performant solution for that might be:
...
WHERE last_update_date >= TO_DATE('03-09-21','DD-MM-YY')
AND last_update_date < TO_DATE('04-09-21','DD-MM-YY')
This makes the comparison without wrapping last_update_date in a TRUNC() function. This could perform better in either of the following circumstances:
If there is an index on last_update_date that would be useful in your query
If the table with last_update_date is large and is being joined to other tables (because it makes it easier for Oracle to estimate the number of rows from your table that are inputs to the join).
Your column might contain hours and seconds, but they can be hidden.
So when you filter on the date, oracle implicitly adds time to the date. So basically you are filtering on '03-09-21 00:00:00'
Try to trunc your column:
select * from TBL_IPCOLO_BILLING_MST
where trunc(LAST_UPDATED_DATE) = '03-09-21';
Hope, I understood your question correctly.
Oracle docs

What's the best practice to filter out specific year in query in Netezza?

I am a SQL Server guy and just started working on Netezza, one thing pops up to me is a daily query to find out the size of a table filtered out by year: 2016,2015, 2014, ...
What I am using now is something like below and it works for me, but I wonder if there is a better way to do it:
select count(1)
from table
where extract(year from datacolumn) = 2016
extract is a built-in function, applying a function on a table with size like 10 billion+ is not imaginable in SQL Server to my knowledge.
Thank you for your advice.
The only problem i see with the query is the where clause which executes a function on the 'variable' side. That effectively disables zonemaps and thus forces netezza to scan all data pages, not only those with data from that year.
Instead write something like:
select count(1)
from table
where datecolumn between '2016-01-01' and '2016-12-31'
A more generic alternative is to create a 'date dimension table' with one row per day in your tables (and a couple of years into the future)
This is an example for Postgres: https://medium.com/#duffn/creating-a-date-dimension-table-in-postgresql-af3f8e2941ac
This enables you to write code like this:
Select count(1)
From table t join d_date d on t.datecolumn=d.date_actual
Where year_actual=2016
You may not have the generate_series() function on your system, but a 'select row_number()...' can do the same trick. A download is available here: https://www.ibm.com/developerworks/community/wikis/basic/anonymous/api/wiki/76c5f285-8577-4848-b1f3-167b8225e847/page/44d502dd-5a70-4db8-b8ee-6bbffcb32f00/attachment/6cb02340-a342-42e6-8953-aa01cbb10275/media/generate_series.tgz
A couple of further notices in 'date interval' where clauses:
Those columns are the most likely candidate for a zonemaps optimization. Add a 'organize on (datecolumn)' at the bottom of your table DDL and organize your table. That will cause netezza to move around records to pages with similar dates, and the query times will be better.
Furthermore you should ensure that the 'distribute on' clause for the table results in an even distribution across data slices of the table is big. The execution of the query will never be faster than the slowest dataslice.
I hope this helps

Obtaining a list of date to control file import

I have a need to pull in via FTP only files from dates I haven't pulled data. The data pulls happen nightly, but occasionally there is an issue and a night gets skipped, and it will be picked up the following night.
I located a query on StackOverflow which addressed most of my problem. However, I'm left with an uncomfortable solution and a lingering question.
I have a table with data from each file downloaded. The crux of the data I'm using for this example is EXTRACT_DATE. The file format is filename_20160809.csv, as an example. Uses the 4-digit year, 2-digit month and 2-digit day to make unique. The FTP location has thousands of files, and I only want to grab the new, based on this date.
First, I get the latest EXTRACT_DATE from my table as such
SELECT MAX(EXTRACT_DATE) INTO checkDate FROM FILE_DETAILS;
I had attempted to do this in a single query, but couldn't work it, and finally attempted to create a variable, checkDate, and use this variable in a subsequent query to obtain my list. However, having two queries in a single script is not allowed, or I haven't found a way to do it. So my primary issue is to return the value of the latest date. Then call a new query or procedure with the value incorporated in to obtain my list, with this query
SELECT TO_DATE(checkDate, 'MM/DD/YYYY') + rownum AS EXTRACT_DATES
FROM ALL_OBJECTS
WHERE TO_DATE(checkDate, 'MM/DD/YYYY') + rownum <= TO_DATE(SYSDATE, 'DD-MM-YY');
This solution is messy and uncomfortable, I would prefer a single query to get back my results, rather then 2 scripts or a script and a procedure.
The lingering question, the result from the query returns dates in the mm/dd/yyyy format; 8/9/2016. I adjusted the TO_DATE to match.
Initially, it was set to return as YYYY-MM-DD; 2016-08-09.
However, it wouldn't return in this format. It would only come back as 8/9/2016, regardless of the TO_DATE formatting used. I don't understand why the date is coming back in this format.
SELECT TO_DATE('2-AUG-2016', 'DD-MON-RR') + rownum AS EXTRACT_DATES
FROM ALL_OBJECTS
WHERE TO_DATE('2-AUG-2016', 'DD-MON-RR') + rownum <= TO_DATE(SYSDATE, 'DD-MM-YY');
EXTRACT_DATES
8/3/2016
8/4/2016
8/5/2016
8/6/2016
8/7/2016
8/8/2016
8/9/2016
NLS_DATE_FORMAT is set to DD-MON-RR, with American as NLS_DATE_LANGUAGE.

Oracle - select statement alias one column and wildcard to get all remaining columns

New to SQL. Pardon me if this question is a basic one. Is there a way for me to do this below
SELECT COLUMN1 as CUSTOM_NAME, <wildcard for remaining columns as is> from TABLE;
I only want COLUMN1 appear once in the final result
There is no way to make that kind of dynamic SELECT list with regular SQL*.
This is a good thing. Programming gets more difficult the more dynamic it is. Even the simple * syntax, while useful in many contexts, causes problems in production code. The Oracle SQL grammar is already more complicated than most traditional programming languages, adding a little meta language to describe what the queries return could be a nightmare.
*Well, you could create something using Oracle data cartridge, or DBMS_XMLGEN, or a trick with the PIVOT clause. But each of those solutions would be incredibly complicated and certainly not as simple as just typing the columns.
This is about as close as you will get.
It is very handy for putting the important columns up front,
while being able to scroll to the others if needed. COLUMN1 will end up being there twice.
SELECT COLUMN1 as CUSTOM_NAME,
aliasName.*
FROM TABLE aliasName;
In case you have many columns it might be worth to generate a full column list automatically instead of relying on the * selector.
So a two step approach would be to generate the column list with custom first N columns and unspecified order of the other columns, then use this generated list in your actual select statement.
-- select comma separated column names from table with the first columns being in specified order
select
LISTAGG(column_name, ', ') WITHIN GROUP (
ORDER BY decode(column_name,
'FIRST_COLUMN_NAME', 1,
'SECOND_COLUMN_NAME', 2) asc) "Columns"
from user_tab_columns
where table_name = 'TABLE_NAME';
Replace TABLE_NAME, FIRST_COLUMN_NAME and SECOND_COLUMN_NAME by your actual names, adjust the list of explicit columns as needed.
Then execute the query and use the result, which should look like
FIRST_COLUMN_NAME, SECOND_COLUMN_NAME, OTHER_COLUMN_NAMES
Ofcourse this is overhead for 5-ish columns, but if you ever run into a company database with 3 digit number of columns, this can be interesting.

"group by day" in Oracle doesn't appear to group by date

My query looks something like this:
select datesent, count(*) the_count from receivedmessaged where status=5000
and datesent>(to_date('20130101', 'YYYYMMDD')) group by datesent
What I'm looking for is a table that has the count of messages with a status of 5000 per day, newer than a certain date. What I'm getting is a table with the same dates over and over. What I think is happening is that there is a hidden time part in that datesent field, and its grouping the entries by the exact time they were sent, rather than just looking at the date. Can anyone confirm this and tell me how I can fix it? Thanks!
What I think is happening is that there is a hidden time part in that datesent field, and its grouping the entries by the exact time they were sent, rather than just looking at the date.
That's very probably what's happening. So try that:
select TRUNC(datesent), count(*) the_count from receivedmessaged where status=5000
and datesent>(to_date('20130101', 'YYYYMMDD')) group by TRUNC(datesent)
TRUNC will remove the "time part" and allow you to group by day.
Please note that the use of TRUNC wil invalidate your index. Take a look at your execution plan. And if needed, you should add a function-based index on TRUNC(datesend).
Of course, using TRUNC would solve your issue, and using a function-based index would make it efficient.
However, from 11g onwards, you could also use VIRTUAL colums. In your case, you can add a virtual column as new_date ALWAYS GENERATED AS (TRUNC(date_column)). You just need to use this virtual column in your query. For performance improvement, if required, you could create an index.
NOTE : Indexes defined against virtual columns are equivalent to function-based indexes.

Resources