SYSDATE FROM DUAL in another SELECT - sql

I have problems with time in my select. Time in DB is different than system time so I guess I need to use SELECT SYSDATE FROM DUAL but it doesn't work in another select. I use PL/SQL Developer.
SELECT t.something1,
ROUND((TRUNC(SELECT SYSDATE FROM DUAL) - 1 + 2),1) AS NAME
FROM customers t
WHERE t.something1 = ROUND((TRUNC(SELECT SYSDATE FROM DUAL) - 1 + 2),1);
I have also tried to declare new variable but I always get error message.
DECLARE
day DATE
SELECT SYSDATE
INTO day
FROM DUAL
SELECT t.something1,
ROUND((TRUNC(day)- 1 + 2),1) AS NAME
FROM customers t
WHERE t.something1 = ROUND((TRUNC(day) - 1 + 2),1);

You must use SELECT SYSDATE FROM DUAL to get SYSDATE only if you have no table to select from. This is because a SELECT without a FROM is not valid with Oracle, so when you want to use a SQL function and you have no table, you have to use DUAL, which is a special one-row one-column (named DUMMY) table. The only row has the value X.

ROUND(number) function will only work with number data type. It will not work with the date type.
If your t.something1 column data type is date than you can't used round() function (you can directly compare date with date), if it not and is number than you will use round() and you need to convert your sysdate into number and compare.
As per my understanding you do something like below :
SELECT t.something1,
ROUND(to_number(to_char(sysdate+1,'DDMMYYYY')),1) AS NAME
FROM customers t
WHERE t.something1 = ROUND(to_number(to_char(sysdate+1,'DDMMYYYY')),1);
May this will help you.

You don't need the subquery:
SELECT t.something1,
ROUND((TRUNC(SYSDATE) - 1 + 2),1) AS NAME
FROM customers t
WHERE t.something1 = ROUND((TRUNC(SYSDATE) - 1 + 2),1);
Does this fix your problem?

Related

How can I get the previous month if the month is kind of number, not a format of time

Now, my case is I have two kinds of variable:
LOG_DTM
LOG_DTM_ID
For the 1): It is store the data about month.
For the 2): It is the data about turning LOG_DTM into number, so it is not an expression of time, just a number.
For example, if the LOG_DTM = OCT 6 2022, then LOG_DTM_ID = 20221006.
The Question is I want to find the last month data from database,
For the LOG_DTM, I am doing in this way(it is working):
select *
from table
where
LOG_DTM between TRUNC(ADD_MONTHS(SYSDATE, -1),'MM')
and LAST_DAY(ADD_MONTHS(TRUNC(SYSDATE,'mm'),-1))
However, for the LOG_DTM_ID, it cannot work:
select *
from table
where
LOG_DTM_ID between to_number(to_charc(TRUNC(ADD_MONTHS(SYSDATE, -1), 'MM')))
and to_number(to_charc(LAST_DAY(ADD_MONTHS(TRUNC(SYSDATE, 'mm'), -1))))
May I know whats wrong with me? Is my logic flow wrong or syntax wrong? Thanks very much.
Use TO_CHAR and not TO_CHARC; and
Include a format model as the second argument to TO_CHAR.
You can simplify the upper bound to TRUNC(SYSDATE,'mm')-INTERVAL '1' SECOND
Select *
from table_name
Where LOG_DTM_ID between to_number(to_char(TRUNC(ADD_MONTHS(SYSDATE, -1),'MM'), 'YYYYMMDDHH24'))
AND to_number(to_char(TRUNC(SYSDATE,'mm')-INTERVAL '1' SECOND, 'YYYYMMDDHH24'))
Which, for the sample data:
CREATE TABLE table_name (
LOG_DTM DATE,
LOG_DTM_ID NUMBER(10,0)
GENERATED ALWAYS AS (TO_NUMBER(TO_CHAR(log_dtm, 'YYYYMMDDHH24')))
);
INSERT INTO table_name (log_dtm)
SELECT ADD_MONTHS(SYSDATE, -1) FROM DUAL;
Outputs:
LOG_DTM
LOG_DTM_ID
2022-09-06 10:15:39
2022090610
fiddle

Find data with specific date and month only

I am trying to find a data with specific where clause of date and month but I am receiving an error can anyone help me with this?
select *
from my_data
where date BETWEEN '11-20' AND '12-15'
MS SQL Server Management Studio
I am receving an error
Conversion failed when converting date and/or time from character string
Most databases support functions to extract components of dates. So, one way of doing what you want is to convert the values to numbers and make a comparison like this:
where month(date) * 100 + day(date) between 1120 and 1215
The functions for extracting date parts differ by database, so your database might have somewhat different methods for doing this.
The conversion is failing because you are not specifying a year. If you were to specify '11-20-2015' your query would work just insert whatever year you need.
SELECT *
FROM my_data
WHERE date BETWEEN '11-20-2015' AND '12-15-2015'
Alternatively if you wanted data from that range of dates for multiple years I would use a while loop to insert information in a # table then read from that table, depending on the amount of data this could be quick or sloooowww here is an example.
DECLARE #mindatestart date, #mindateend date, #maxdatestart date
SET #mindatestart = '11-20-2010'
SET #mindateend = '12-15-2010'
SET #maxdatestart = '11-20-2015'
SELECT top 0 *, year = ' '
INTO #mydata
FROM my_data
WHILE #mindatestart < #maxdatestart
BEGIN
INSERT INTO #mydata
SELECT *, YEAR(#mindatestart)
FROM my_data
where date between #mindatestart and #mindateend
SET #mindatestart = DATEADD(Year, 1, #mindatestart)
SET #mindateend = DATEADD(Year, 1, #mindateend)
END
This will loop and insert the data from 2010-2015 for those date ranges and add a extra column on the end so you can call the data and order by year if you want like this
SELECT * FROM #mydata order by YEAR
Hopefully some part of this helps!
FROM THE COMMENT BELOW
SELECT *
FROM my_data
WHERE DAY(RIGHT(date, 5)) between DAY(11-20) and DAY(12-15)
The reason '11-20' doesn't work is because its a character string which is why you have to input it between ' ' What the Month() function does is take whatever you put between the () and convert it to an integer. Which is why you're not getting anything back using the method in the first answer, the '-Year' from the table date field is being added into the numeric value where your value is just being converted from 11-20 you can see by using these queries
SELECT MONTH(11-20) --Returns 12
SELECT MONTH(11-20-2015) -- Returns 6
SELECT MONTH(11-20-2014) -- Returns 6
Using RIGHT(Date, 5) you only get Month-day, then you date the day value of that so DAY(RIGHT(DATE, 5) and you should get something that in theory should fall within those date ranges despite the year. However I'm not sure how accurate the data will be, and its a lot of work just to not add an additional 8 characters in your original query.
Since you only care about month and day, but not year, you need to use DATEPART to split up the date. Try this:
select *
from my_data
WHERE 1=1
AND (DATEPART(m, date) >= 11 AND DATEPART(d,date) >= 20)
AND (DATEPART(m, date) <= 12 AND DATEPART(d,date) <= 15)

Recursive Query for Date Range

I'm trying to create a query so that I can generate a date range between a specific start and end point.
I have the following:
WITH DATE_RANGE(DATE_FOR_SHIFT)
AS (SELECT DATE('2015-04-01')
FROM SYSIBM.SYSDUMMY1
UNION ALL
SELECT DATE_FOR_SHIFT + 1 DAY
FROM DATE_RANGE
WHERE DATE_FOR_SHIFT <= #END)
SELECT DATE_FOR_SHIFT
FROM DATE_RANGE;
Output (assuming that #END equals 2015-05-01):
2015-04-01
2015-04-02
2015-04-03
2015-04-04
...
2015-05-01
The output is correct, but I want to be able to change the start and points based on parameters provided rather than having to rewrite the query or have a SQL injection prone query.
How would I rewrite this query in order to accomplish this?
Your SELECT is fine, other than the hard coded start date.
What I think you're missing is wrapping it in either a stored procedure or user defined table function (UDTF). Assuming you'll want to JOIN the date range to other tables, I'd suggest a UDTF.
create function date_range (#str date, #end date)
returns table (date_for_shift date)
language SQL
reads SQL data
return
WITH DATE_RANGE(DATE_FOR_SHIFT)
AS (SELECT #str
FROM SYSIBM.SYSDUMMY1
UNION ALL
SELECT DATE_FOR_SHIFT + 1 DAY
FROM DATE_RANGE
WHERE DATE_FOR_SHIFT <= #END)
SELECT DATE_FOR_SHIFT
FROM DATE_RANGE;
Then you'd call it...
select * from table(date_range(date('2015-04-01'),date('2015-05-01'))) as tbl;
However, instead of generating this date range on the fly....consider simply creating a calender (aka dates) table. Basically just a table with dates from say 1900-01-01 to 2500-12-31..or whatever you'd like. Beside the date column, you can include lots of additional columns such as business_day, holiday, ect.. that make life much easier.
Google "SQL calendar table" for plenty of examples.
A bit of playing with this in perl gives me:
#!/opt/myperl/5.20.2/bin/perl
use 5.10.0;
use DBI;
use DBD::DB2;
use Data::Dump;
my $sql = <<EOSQL;
WITH DATE_RANGE(DATE_FOR_SHIFT)
AS (SELECT CAST(? AS DATE)
FROM SYSIBM.SYSDUMMY1
UNION ALL
SELECT DATE_FOR_SHIFT + 1 DAY
FROM DATE_RANGE
WHERE DATE_FOR_SHIFT < CAST(? AS DATE))
SELECT DATE_FOR_SHIFT
FROM DATE_RANGE;
EOSQL
my $dbh = DBI->connect('dbi:DB2:sample');
my $sth = $dbh->prepare_cached($sql);
$sth->execute('2015-04-01','2015-05-01');
my $rc = $sth->fetchall_arrayref();
dd($rc);
This does give an error during prepare ("The recursive common table expression "MYSCHEMA.DATE_RANGE" may contain an infinite loop") that I haven't figured out yet, but the fetch does work, the final return goes from 04-01 to 05-01. Hopefully you can port this to your desired language.

PLSQL 'IN' Operator

I'm trying to select rows based on a range of 'dates' determined by the following PLSQL query, which currently delivers the results I need - being the 'date' object of the last 10 weeks of the day of the week when the script is run. Eg. running it on the 22th of May would yield, 15th May, 8th May and so on.
SELECT SYSDATE-(level*7) as DateRange
FROM DUAL
CONNECT BY LEVEL <=10
This generates a list of dates. Then I try and combine this with a parent select statement to get rows with the dates outputted by the above that are in the 'DAY' (of Oracle type DATE) column.
SELECT * FROM NEM_RM16
WHERE NEM_RM16.DAY IN (
SELECT SYSDATE-(level*7) as DateRange
FROM DUAL
CONNECT BY LEVEL <=10);
Which gives no results, despite knowing that there are rows that have the dates generated by the above.
I've read that when using the 'IN' operator, values must be enclosed in single quotes, but I'm not sure about how to do this with the query above.
Am I going about this the right way by using the IN operator, or should I be doing a different type of nested query?
use trunc for truncate time component from sysdate
SELECT * FROM NEM_RM16
WHERE NEM_RM16.DAY IN (
SELECT trunc(SYSDATE)-(level*7) as DateRange
FROM DUAL
CONNECT BY LEVEL <=10);
Maybe the format of the date returned by nested query does not match with the date format of the column NEM_RM16.DAY
Probably, if the dates are compared after making them of the same format, they will match properly
Like this
SELECT *
FROM NEM_RM16
WHERE TO_DATE(TO_CHAR(NEM_RM16.DAY, 'DD/MM/YYYY'), 'DD/MM/YYYY') IN
(SELECT TO_DATE(TO_CHAR(SYSDATE - (level * 7), 'DD/MM/YYYY'),
'DD/MM/YYYY') as DateRange
FROM DUAL
CONNECT BY LEVEL <= 10);
Hope it helps

Teradata - Invalid Date supplied for FIELD

I'm trying to query a table that has a varchar(100) "VALUE" column. This column can hold anything from a letter, a number or, in this case, a date.
The date will always be entered in the table as 'YYYY-mm-dd'. However, when I run the following query:
select * from myTable
where VALUE = '2009-12-11' (Date, Format 'yyyy-mm-dd')
I receive the following error:
Invalid date supplied for myTable.VALUE.
Example of the value table:
(1,'122')
(2,'red')
(3,'2009-12-11')
Any ideas as to what might be causing this?
Thanks!
if the data type is declared as varchar, it should just treat it like a string.
try not specifying anything about the date format, like
select * from myTable
where VALUE = '2009-12-11'
If you run an explain on the query, you can see that it's casting value to date before comparing against your supplied value. If you have another column that accurately records the type of what's in VALUE, you can add that to the where clause and you will no longer get the error (see below). Otherwise, go with Beth's recommendation.
select * from myTable
where VALUE = '2009-12-11' (Date, Format 'yyyy-mm-dd')
and VALUE_TYPE = 'DATE';
Teradata internal date calculation is (year - 1900) * 10000 + (month * 100) + day.
So if date is 02/11/2009 (2nd November 2010) then
=(2009-1900) * 10000 + (11 * 100) + 2
=109 * 10000 + 1100 + 2
=1090000 + 1100 + 2
=1090000
1100
2
----------
1091102
----------
So 2nd november 2009 is stored in Teradata as 1091102.
You can extract it in required format by casting (as u have it in varchar). Hope this helps.
Is it possible that VALUE is a reserved word in Teradata?
If so, you need to put that into double quotes:
select *
from myTable
where "VALUE" = '2009-12-11'