select only specific dates oracle sql - sql

I have got an example query like
select cu.customer_no
from customers.cu
where cu.audit_date like '01-FEB-14'
The problem is that I would like to retrieve data only for specific dates which are the first day of the month and skip all of them in between. The desired query should be something like
select cu.customer_no
from customers.cu
where cu.audit_date like ('01-FEB-14', '01-JAN-14', '01-MAY-14')

Assuming that audit_date is a date, not a varchar2, if you are certain that the time component is always midnight, you can do
WHERE cu.audit_date = trunc(cu.audit_date, 'MM')
If there may be a non-midnight time component and you want to ignore the time component, you can do
WHERE trunc(cu.audit_date) = trunc(cu.audit_date, 'MM')
Alternately, you can use to_char
WHERE to_number( to_char( cu.audit_date, 'DD' ) ) = 1

select cu.customer_no
from customers.cu
where cu.audit_date
in (select distinct trunc(audit_date ,'MM') from customers);

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

sql pivot function with a defined variable in the IN statement

Can anyone tell me how I can make this work? I either get "ORA-56901: non-constant expression is not allowed for pivot|unpivot values" or I get "ORA-00917: missing comma" depending on whether I put &mb1 in quotes or not in the IN statement. Thank you!
define mb1= ADD_MONTHS(TRUNC(SYSDATE,'MM'),-1);
select *
from
( select COLLECTOR
,Month
,low_activity_days
from dwh_prod.low_activity_days_collect_t) src
pivot
(
sum(low_activity_days)
for month in ('&mb1')
) piv;
You could set your substitution to a fixed value instead, so it isn't trying to to a calculation inside the pivot clause. As you're working with dates you can generate a date literal:
set termout off
column x_mb1 new_value mb1
select 'date ''' || TO_CHAR(ADD_MONTHS(TRUNC(SYSDATE,'MM'),-1),
'YYYY-MM-DD') || '''' as x_mb1
from dual;
set termout on
select * from (
select COLLECTOR ,Month ,low_activity_days
from dwh_prod.low_activity_days_collect_t
) src
pivot ( sum(low_activity_days) for month in (&mb1) ) piv;
The first query - with the output hidden by termout generates a string:
select 'date ''' || TO_CHAR(ADD_MONTHS(TRUNC(SYSDATE,'MM'),-1),
'YYYY-MM-DD') || '''' as x_mb1
from dual;
X_MB1
-----------------
date '2017-03-01'
The column ... new_value command then sets &mb to that. The substitution in your really query then becomes:
select * from (
select COLLECTOR ,Month ,low_activity_days
from dwh_prod.low_activity_days_collect_t
) src
pivot ( sum(low_activity_days) for month in (date '2017-03-01') ) piv
The problem with your original code is that you're ending up with a reference to sysdate inside the substituted pivot clause, which throws the ORA-56901 exception (since sysdate isn't constant). You can use any fixed value in the pivot, so you could do:
define mb1=''01-APR-17''
... for month in (&mb1) ) piv;
with the qoutes around the string as part of the definition, or
define mb1='01-APR-17'
... for month in ('&mb1') ) piv;
without, or other variations. But because those end up as string you're relying on implicit date conversion, and relying on your NLS settings; with the date literal I'm generating that isn't an issue. If you really wanted to use that date format you could still do:
define mb1='01-APR-17'
... for month in (to_date('&mb1', 'DD-MON-RR')) ) piv;
or select the date in that specific format with the new_values method:
column x_mb1 new_value mb1
select to_char(add_months(trunc(sysdate, 'MM'), -1), 'DD-MON-RR') as x_mb1 from dual;
... for month in (to_date('&mb1', 'DD-MON-RR')) ) piv;
Using the date literal format still seems simpler to me though.
I'm not sure why pivoting a single value is particularly useful though. Maybe your real query is doing more, but simple aggregation and a filter look more appropriate here:
select collector, sum(low_activity_days)
from low_activity_days_collect_t
where month = add_months(trunc(sysdate, 'MM'), -1)
group by collector;
If you want a rolling 12-month summary you don't need to build the pivot quite that dynamically; you can generate a month-offset number based on the current date, which will give you a fixed range of numeric values you can pivot on (rather than dates), something like:
select * from (
select collector, low_activity_days,
months_between(trunc(sysdate, 'MM'), month) as month_offset
from low_activity_days_collect_t
where month >= add_months(trunc(sysdate, 'MM'), -13)
and month < trunc(sysdate, 'MM')
) src
pivot (sum(low_activity_days) as months_ago
for month_offset in (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12));
which will give columns collector, 1_months_ago, 2_months_ago etc.
What you can't easily do is make the column headings represent the actual month (e.g. 2017-04, 2017-03, ...), but you don't seem to have been trying to do that anyway; and unless you alias the pivoted column terms the ones generated in this example have to be treated as quoted identifiers (because they start with numbers).
If you do want month headers you could generate those with some more substitution variable shenanigans, with something like this before the query:
set termout off
column x_m1 new_value m1
column x_m2 new_value m2
...
column x_m12 new_value m12
select to_char(add_months(trunc(sysdate, 'MM'), -1), 'YYYY-MM') as x_m1,
to_char(add_months(trunc(sysdate, 'MM'), -2), 'YYYY-MM') as x_m2,
...
to_char(add_months(trunc(sysdate, 'MM'), -12), 'YYYY-MM') as x_m12
from dual;
column 1_months_ago heading &m1
column 2_months_ago heading &m2
...
column 12_months_ago heading &m12
set termout on
You might find it easier to use a proper reporting tool to query and format/display the results for you though.

Oracle - Format return of sysdate inside select

I did a select in oracle database to return the time that ticket is in a support group.
Sometimes, I have the scenario where we have the date of ticket joined the group, but I'm not out of time.
To workaround this problem, I put in my select a condition and worked with diff between the date of entry in the group and the sysdate.
The problem is the output that is being formatted as follows: +00 00:28:32.00000, and I need only the time in minutes.
Below, I added the whole query, I suppose that the problem is in this part:
CASE
WHEN PBTI_TEMPONOGRUPO IS NULL
THEN (SYSDATE-(SECS_TO_DATE(PBTI_DATAENTRADAGRUPO)))
END AS TEMPO_NO_GRUPO
How to format this output?
The query is:
SELECT PBTI_WORKORDER_ID AS ID_WO,
PBTI_IDREQUISICAO AS ID_REQ,
PBTI_GRUPOSUPORTEATUAL AS GRUPO_SUP_ATUAL,
PBTI_GRUPOSUPORTEANTERIOR AS GRUPO_SUP_ANTERIOR,
CASE
WHEN PBTI_DATASAIDAGRUPO IS NULL
THEN SYSDATE
WHEN PBTI_DATASAIDAGRUPO IS NOT NULL
THEN SECS_TO_DATE(PBTI_DATASAIDAGRUPO)
END AS DATA_SAIDA_GRUPO,
SECS_TO_DATE(PBTI_DATAENTRADAGRUPO) AS DATA_ENTRADA,
CASE
WHEN PBTI_TEMPONOGRUPO IS NULL
THEN (SYSDATE-(SECS_TO_DATE(PBTI_DATAENTRADAGRUPO)))
END AS TEMPO_NO_GRUPO
FROM PBTI_TABELA_INDICADORES
WHERE PBTI_WORKORDER_ID = 'WO0000000142585';
CASE
WHEN PBTI_DATASAIDAGRUPO IS NULL
THEN SYSDATE
WHEN PBTI_DATASAIDAGRUPO IS NOT NULL
THEN SECS_TO_DATE(PBTI_DATASAIDAGRUPO)
END
So the output of the CASE expressions will be DATE data type. To get the output in your desired format, use TO_CHAR along with desired FORMAT MODEL to convert it into a string.
For example,
SQL> SELECT TO_CHAR(SYSDATE, 'YYYY-MM-DD') only_date FROM DUAL;
ONLY_DATE
----------
2015-10-20
SQL> SELECT TO_CHAR(SYSDATE, 'HH24:MI:SS') only_time FROM DUAL;
ONLY_TIME
---------
20:29:54

Selecting YYYYMM of the previous month in HIVE

I am using Hive, so the SQL syntax might be slightly different. How do I get the data from the previous month? For example, if today is 2015-04-30, I need the data from March in this format 201503? Thanks!
select
employee_id, hours,
previous_month_date--YYYYMM,
from
employees
where
previous_month_date = cast(FROM_UNIXTIME(UNIX_TIMESTAMP(),'yyyy-MM-dd') as int)
From experience, it's safer to use DATE_ADD(Today, -1-Day(Today)) to compute last-day-of-previous-month without having to worry about edge cases. From there you can do what you want e.g.
select
from_unixtime(unix_timestamp(), 'yyyy-MM-dd') as TODAY,
date_add(from_unixtime(unix_timestamp(), 'yyyy-MM-dd'), -1-cast(from_unixtime(unix_timestamp(), 'd') as int)) as LAST_DAY_PREV_MONTH,
substr(date_add(from_unixtime(unix_timestamp(), 'yyyy-MM-dd'), -1-cast(from_unixtime(unix_timestamp(), 'd') as int)), 1,7) as PREV_MONTH,
cast(substr(regexp_replace(date_add(from_unixtime(unix_timestamp(), 'yyyy-MM-dd'), -1-cast(from_unixtime(unix_timestamp(), 'd') as int)), '-',''), 1,6) as int) as PREV_MONTH_NUM
from WHATEVER limit 1
-- today last_day_prev_month prev_month prev_month_num
-- 2015-08-13 2015-07-30 2015-07 201507
See Hive documentation about date functions, string functions etc.
below works across year boundaries w/o complex calcs:
date_format(add_months(current_date, -1), 'yyyyMM') --previous month's yyyyMM
in general,
date_format(add_months(current_date, -n), 'yyyyMM') --previous n-th month's yyyyMM
use proper sign for needed direction (back/ahead)
You could do (year('2015-04-30')*100+month('2015-04-30'))-1 for the above mentioned date, it will return 201503 or something like (year(from_unixtime(unix_timestamp()))*100+month(from_unixtime(unix_timestamp())))-1 for today's previous month. Assuming your date column is in 'yyyy-mm-dd' format you can use the first example and substitute the date string with your table column name; for any other format the second example will do, add the column name in the unix_timestamp() operator.
Angelo's reply is a good start but it returns 201500 if the original date was 2015-01-XX. Building on his answer, I suggest using the following:
IF(month(${DATE}) = 1,
(year(${DATE})-1)*100 + 12,
year(${DATE})*100 + month(${DATE})-1
) as month_key
provided you get rid of those hyphens in your input string , previous date's month id in YYYYMM format you can get by:-
select if( ((${hiveconf:MonthId}-1)%100)=0 ,${hiveconf:MonthId}-89,${hiveconf:MonthId}-1 ) as PreviousMonthId;

Getting only day and month from a date field

I have a set of dates that are in the format DD-MMM-YYYY. I need to be able to compare dates by using only the DD-MMM part of the date, since the year isn't important.
How would I achieve this?
I have tried reading up on the DATEPART function (edit: which evidently wouldn't work) but I can only theoretically get that to return either the DD or the MMM parts, not both of them at once.
Edit: added oracle tag. Sorry.
Example of date field: 01-MAR-1994
If your column is of type DATE then it doesn't have a format.
If I understand you right, then you want to view the mon-dd part only, so you need to convert it with TO_CHAR function,
i.e.:
select to_char(your_date_column, 'mon-dd') from your_table
Convert your dates using the following format, it will only month and the date part. You have to replace getdate() with you date fields.:
select convert(varchar(5),getdate(),110)
Assuming that you are using SQL Server or Oracle since you attempted using DATEPART, you can just get the day and month using the DAY() and MONTH() functions. Assuming, again, that the dates you are comparing are in two different tables, it would look similar to this:
SELECT MONTH(t1.date), DAY(t2.date)
FROM table AS t1
INNER JOIN table2 AS t2
ON t1.key = t2.key
WHERE MONTH(t1.date) = MONTH(t2.date)
AND DAY(t1.date) = DAY(t2.date)
EDIT: If you are just comparing rows in the same table, you only need a very simple query.
SQLFiddle
select id, TO_CHAR(most_recent, 'mon-dd')
from (
select id, MAX(date1) AS most_recent
from table1
group by id
)
You can also combine month and day into one integer:
EXTRACT(MONTH FROM datecol) * 100 + EXTRACT(DAY FROM datecol) AS MonthDay
Then it's easier to sort and compare.
select FORMAT(yourcoulmn_name, 'dd/MM') from table
This should do the trick
`select CONVERT(varchar(7),datetime_column,100) from your_table`
date_default_timezone_set("Asia/Kolkata");
$m = date("m");//Month
$d = date("d");//Day
$sql = "SELECT * FROM contactdata WHERE MONTH(date) = '$m' AND DAY(date) = '$d' ";
only checks day and month and returns today, day and month from database
SELECT LEFT(REPLACE(CONVERT(varchar(10),GETDATE()-1,3),'/',''),4)
WOuld this work for you?
FROMAT(DATETIME, 'dd-MMM') = FROMAT(DATETIME, 'dd-MMM') use any format you want