Oracle: extract year from date in listagg - oracle

I have a table with date column and would like to obtain a string with distinct years:
ID DATA
1 01/01/2010
2 02/01/2010
3 01/03/2011
4 03/01/2014
5 05/02/2014
From the above table and using listagg I want to get the years
2010
2011
2014
But when I run the following query:
SELECT LISTAGG(EXTRACT(year from data),',')
WITHIN GROUP (ORDER BY data)
FROM (SELECT distinct EXTRACT(year from data)
FROM t_teste)
I get the following error
ORA-00904: "DATA": invalid identifier
Any idea what I'm doing wrong?

You're using a subquery that is not specifying an alias for your extracted year value, and the data column from your table is no longer visible - as it is only in scope inside the subquery.
You can add a column alias and then refer to that directly in the outer query, without needing another extract:
select listagg(anno, ',') within group (order by anno)
from (
select distinct extract(year from data) as anno
from t_teste
);
LISTAGG(ANNO,',')WITHINGROUP(ORDERBYANNO)
-----------------------------------------
2010,2011,2014

Related

How can I get the Year to Date (YTD) count of data using Oracle?

How can I get the Year to Date (YTD) count of a certain data using Oracle query?
Assume that we are interested in summing the total number of vouchers filed since the beginning of the current year.
This is the query I came up with
WITH cteDAYSCOUNT AS (SELECT TO_NUMBER(TO_CHAR(SYSDATE, 'DDD'))
FROM dual)
SELECT COUNT(VOUCHER_FILED_DATE), SYSDATE AS "AS OF" FROM CLAIMS
WHERE VOUCHER_FILED_DATE > sysdate - cteDAYSCOUNT;
This part of it returns the number of days since the beginning of the year
WITH cteDAYSCOUNT AS (SELECT TO_NUMBER(TO_CHAR(SYSDATE, 'DDD')) FROM dual)
And this part attempts to use the sysdate - {number of days} to calculate the count
SELECT COUNT(VOUCHER_FILED_DATE), SYSDATE AS "AS OF"
FROM CONTINUED_CLAIMS WHERE VOUCHER_FILED_DATE > sysdate - cteDAYSCOUNT;
But the problem is the although cteDAYSCOUNT holds the number of days since the year starts, it is not being recognized as a number, so it's throws an error
Is there a better query for calculating YTD count or a fix of the above query?
I'm not sure I'm following you.
Query you posted is incomplete; CTE lacks in column name, while FROM clause misses join with the CTE. Therefore, your query can't work at all.
If it is fixed, then:
SQL> WITH
2 ctedayscount (ctedayscount) AS
3 -- this is yours
4 (SELECT TO_NUMBER (TO_CHAR (SYSDATE, 'DDD')) FROM DUAL),
5 claims (voucher_filed_date) AS
6 -- this is my CTE, so that query would actually return something
7 (SELECT DATE '2021-01-15' FROM DUAL)
8 -- final SELECT; you're missing JOIN with CTEDAYSCOUNT
9 SELECT COUNT (voucher_filed_date), SYSDATE AS "AS OF"
10 FROM claims CROSS JOIN ctedayscount
11 WHERE voucher_filed_date > SYSDATE - ctedayscount;
COUNT(VOUCHER_FILED_DATE) AS OF
------------------------- ----------
1 09.02.2021
SQL>
So, it works.
Furthermore, you said:
But the problem is the although cteDAYSCOUNT holds the number of days since the year starts, it is not being recognized as a number, so it's throws an error
How do you know it isn't a NUMBER? Which error is it? It is difficult to debug an unknown error. Could it, perhaps, be that CLAIMS table's voucher_filed_date datatype is something different than DATE (such as VARCHAR2) and contains data which Oracle can't implicitly convert to DATE so WHERE clause (my line #11) fails?
Or is the main problem the fact that you just missed to join CTEDAYSCOUNT with CLAIMS (which I already mentioned)?

Oracle date formatting error - ORA-00933: SQL command not properly ended

I am trying to execute a simple query (ORACLE DB) to display two date columns (START_TIME & END_TIME) along with total counts along with percentage and filtered by a month followed by year the data type defined in the for the two date fields in db as date, i am trying to display the data in the below format
sample data no time stamp
start_time - 01.12.2020
end_time - 02.12.2020
Query
SELECT
to_char(cast(START_TIME as date),'YYYY') as START_BY_YEAR ,
to_char(cast(END_TIME as date),'YYYY') as END_BY_YEAR ,
to_char(cast(START_TIME as date),'MM.YYYY')as START_BY_MONTH,
to_char(cast(END_TIME as date),'MM.YYYY') as END_BY_MONTH,
to_char(cast(START_TIME as date),'DD.MM.YYYY') as START_BY_DAY,
to_char(cast(END_TIME as date),'DD.MM.YYYY') as END_BY_DAY,
COUNT(*) as count,
round(100*ratio_to_report(count(*)) over (), 4) percentage
FROM SCHEMA_NAME.TABLE_NAME
WHERE to_char(cast(START_TIME as date),'MM.YYYY')='12.2020'
and to_char(cast(END_TIME as date),'MM.YYYY')='12.2020'
GROUP BY
START_BY_YEAR,
END_BY_YEAR,
START_BY_MONTH,
END_BY_MONTH,
START_BY_DAY,
END_BY_DAY
order by
START_BY_YEAR desc,
END_BY_YEAR desc,
START_BY_MONTH desc,
END_BY_MONTH desc,
START_BY_DAY desc,
END_BY_DAY desc
I am getting error message
ORA-00904: "END_BY_DAY": invalid identifier
00000 - "%s: invalid identifier"
*Cause:
*Action:
Error at Line: 19 Column: 1
where exactly i am getting error is not clear
expected result set
START_BY_YEAR END_BY_YEAR START_BY_MONTH END_BY_MONTH START_BY_DAY END_BY_DAY
2012 2012 12.2012 12.2012 01.12.2020 02.12.2020
Please note i have expanded the code for easily readable purpose.
Suggestion ?
To solve the error, you have to remove the aliases from the GROUP BY clause.
Also, if your table has date columns, you don't need CASTs and the query can be re-wrtten as:
SELECT
to_char(START_TIME,'YYYY') START_BY_YEAR ,
to_char(END_TIME,'YYYY') END_BY_YEAR ,
to_char(START_TIME,'MM.YYYY') START_BY_MONTH,
to_char(END_TIME,'MM.YYYY') END_BY_MONTH,
to_char(START_TIME,'DD.MM.YYYY') START_BY_DAY,
to_char(END_TIME,'DD.MM.YYYY') END_BY_DAY,
COUNT(*) as count,
round(100*ratio_to_report(count(*)) over (), 4) percentage
FROM TABLE_NAME
WHERE to_char(START_TIME,'MM.YYYY')='12.2020'
and to_char(END_TIME,'MM.YYYY')='12.2020'
GROUP BY
to_char(START_TIME,'YYYY') ,
to_char(END_TIME,'YYYY') ,
to_char(START_TIME,'MM.YYYY') ,
to_char(END_TIME,'MM.YYYY') ,
to_char(START_TIME,'DD.MM.YYYY') ,
to_char(END_TIME,'DD.MM.YYYY')
order by
START_BY_YEAR desc,
END_BY_YEAR desc,
START_BY_MONTH desc,
END_BY_MONTH desc,
START_BY_DAY desc,
END_BY_DAY desc
With a table like this:
create table table_name as
(
select date '2020-12-01' start_time,
date '2020-12-02' end_time
from dual
);
The query gives:
START_BY_YEA END_BY_YEAR START_BY_MON END_BY_MONTH START_BY_DAY END_BY_DAY COUNT PERCENTAGE
------------ ------------ ------------ ------------ ------------ ------------ ----- ----------
2020 2020 12.2020 12.2020 01.12.2020 02.12.2020 1 100
1 row selected.
First check the partial result of:
select cast(END_TIME as date),'DD.MM.YYYY') as END_BY_DAY
FROM SCHEMA_NAME.TABLE_NAME
from the results you can learn about the NLS format of your machin and wrap it with custom to_char format.

Applying where condition on Casted number coulmn in ORACLE from a inner query result

For Sample purpose lets create a table with below schema and fill some sample values
CREATE TABLE games(ID INT ,Name VARCHAR(20));
INSERT INTO games(ID,Name) VALUES (2008,'Beijing');
INSERT INTO games(ID,Name) VALUES (2012,'London');
INSERT INTO games(ID,Name) VALUES (2012,12);
INSERT INTO games(ID,Name) VALUES (2012,654);
Output:
ID NAME
2008 Beijing
2012 London
2012 12
2012 654
In the above table we have both number and string data in the name column lets write a query that uses the REGX to filter only the numerical rows
SELECT TO_NUMBER(Name)as Trimmed FROM games where REGEXP_LIKE(Name, '(?<=\s|^)\d+(?=\s|$)', '')
Output:
TRIMMED
12
654
Now here is the problem if write a where clause of getting values greater than 12 from the above result it throws invalid number.
Select * from (SELECT TO_NUMBER(Name)as Trimmed FROM games where REGEXP_LIKE(Name, '(?<=\s|^)\d+(?=\s|$)', '')) T1 where T1.Trimmed >12 ;
I found this is how the oracle query planning works but is there any other way i can achieve this
This will work:
Select * from
(SELECT Name as Trimmed
FROM games where REGEXP_LIKE(Name, '(?<=\s|^)\d+(?=\s|$)', '')) T1
where to_number(T1.Trimmed) >12 ;
Unfortunately you need a subquery. It can't be done with one where.
This can be done in a single query:
with
inputs as (
select 2008 as id, 'Beijing' as name from dual union all
select 2012 , 'London' from dual union all
select 2012 , '12' from dual union all
select 2012 , '654' from dual
)
select id, name
from inputs
where translate(name, 'a0123456789', 'a') is null
and to_number(regexp_replace(name, '[^[:digit:]]', '')) > 12
;
ID NAME
---------- -------
2012 654
1 row selected.
regexp_replace removes all the characters except digits, so the test can be done regardless of what the name is. If there are no digits in the name, the result is NULL, which can be converted to number (it is still null).
The translate solution for testing for "all-digits" is more efficient than using regexp_like. The odd-looking 'a' in translate is needed due to an oddity in the translate function itself (see the documentation). This test is not needed if all the names are either "all letters" or "all digits" (if "all letters", the second test with regexp_replace would suffice); but the first test is needed if names like "Sydney 2000" are possible in the name column.

How to query view in oracle with non column in view

I have created a view as
create or replace view view_emp as
select empno, ename, job
from emp;
and I want to query view_query with non column in view.
select empno, ename
from view_emp
where deptno=10;
When Im trying to query like this it is giving me an error saying
ORA-00904: "TEST_EMP"."DEPTNO": invalid identifier
I have a requirement like this example. Could any one can give me solution for my requirement.
Actually I work on ERP Solutions Inventory Modules.
I have a requirement to find the unit wise , prodct wise stock opening balance and closing balance in date range.
I want a view like
create view stk_bal
as
select unit_code,prod_code, sum(opening_bal) opening_bal, sum(closing_bal) closing_bal
from
(
select unit_code, prod_code, ob_qty opeing_bal, 0 closing_bal
from (table 1) join (table 1.1)
where crtd_date between '02-feb-2013' and '02-mar-2013'
union all
select unit_code, prod_code, 0 , grn_qty
from (table 2) join (table 2.1)
where grn_date between '02-feb-2013' and '02-mar-2013'
union all
select unit_code, prod_code, 0, stk_transfer_in_qty
from (table 3) join (table 3.1)
where stk_trnin_date between '02-feb-2013' and '02-mar-2013'
)
group by unit_code, prod_code;
and I created view by making union all with 3 set of tables where i had hardcoded the dates
But i want to query the view in date range which has no date column in it.
Now I want to query the the view stk_bal in the date range.
You need to add deptno in your view definition:
create or replace view view_emp as
select empno, ename, job
,DEPTNO
from emp;
But of course, the real question is: what exactly is your requirement and why do you need a view.

pl-sql include column names in query

A weird request maybe but. My boss wants me to create an admin version of a page we have that displays data from an oracle query in a table.
The admin page, instead of displaying the data (query returns 1 row), needs to return the table name and column name
Ex: Instead of:
Name Initial
==================
Bob A
I want:
Name Initial
============================
Users.FirstName Users.MiddleInitial
I realize I can do this in code but would rather just modify the query to return the data I want so I can leave the report generation code mostly alone.
I don't want to do it in a stored procedure.
So when I spit out the data in the report using something like:
blah blah = MyDataRow("FirstName")
I can leave that as is but instead of it displaying "BOB" it would display "Users.FirstName"
And I want to do the query using select * if possible instead of listing all the columns
So for each of the columns I am querying in the * , I want to get (instead of the column value) the tablename.ColumnName or tablename|columnName
hope you are following- I am confusing myself...
pseudo:
select tablename + '.' + Columnname as WhateverTheColumnNameIs
from Table1
left join Table2 on whatever...
Join Table_Names on blah blah
Whew- after writing all this I think I will just do it on the code side.
But if you are up for it maybe a fun challenge
Oracle does not provide an authentic way(there is no pseudocolumn) to get the column name of a table as a result of a query against that table. But you might consider these two approaches:
Extract column name from an xmltype, formed by passing cursor expression(your query) in the xmltable() function:
-- your table
with t1(first_name, middle_name) as(
select 1,2 from dual
), -- your query
t2 as(
select * -- col1 as "t1.col1"
--, col2 as "t1.col2"
--, col3 as "t1.col3"
from hr.t1
)
select *
from ( select q.object_value.getrootelement() as col_name
, rownum as rn
from xmltable('//*'
passing xmltype(cursor(select * from t2 where rownum = 1))
) q
where q.object_value.getrootelement() not in ('ROWSET', 'ROW')
)
pivot(
max(col_name) for rn in (1 as "name", 2 as "initial")
)
Result:
name initial
--------------- ---------------
FIRST_NAME MIDDLE_NAME
Note: In order for column names to be prefixed with table name, you need to list them
explicitly in the select list of a query and supply an alias, manually.
PL/SQL approach. Starting from Oracle 11g you could use dbms_sql() package and describe_columns() procedure specifically to get the name of columns in the cursor(your select).
This might be what you are looking for, try selecting from system views USER_TAB_COLS or ALL_TAB_COLS.

Resources