If I run the following statement as part of a sql script
-- create the pivot_sales_data table
CREATE TABLE pivot_sales_data AS
SELECT *
FROM (
SELECT month, prd_type_id, amount
FROM all_sales
WHERE year = 2003
AND prd_type_id IN (1, 2, 3)
)
PIVOT (
SUM(amount) FOR month IN (1 AS JAN, 2 AS FEB, 3 AS MAR, 4 AS APR)
)
ORDER BY prd_type_id;
I get the ORA-00933: SQL Command nor properly ended error. What am I missing here?
Your pivot doesn't really work. I'm specifically thinking about:
FOR month IN (1 AS JAN, 2 AS FEB, 3 AS MAR, 4 AS APR)
In doesn't really work that way. You either want:
FOR month IN ('JAN', 'FEB', 'MAR', 'APR')
-- or
FOR month IN (1,2,3,4)
Related
i have a query and I want to calculate the number of sat+sun total count in oracle, for example, I have a query pasted below there should be a total count of Saturday and Sunday, how can I achieve that please help, I really appreciate any help you can provide.
SELECT TO_DATE('01-12-2022','dd-mm-yyyy') start_date , TO_DATE(sysdate) end_date
FROM dual;
Don't use a row-generator to create a calendar (as it is very inefficient); just calculate the number by calculating the number of full weeks and then deal with the part weeks at the start and end of the range:
WITH range (start_date, end_date) AS (
SELECT DATE '2022-12-01', TRUNC(SYSDATE) FROM DUAL
)
SELECT -- Number of full weeks
(TRUNC(end_date, 'IW') - TRUNC(start_date, 'IW')) * 2/7
-- Number of weekend days in final week
+ GREATEST(end_date - TRUNC(end_date, 'IW') - 4, 0)
-- Number of weekend days in before first week
- GREATEST(start_date - TRUNC(start_date, 'IW') - 5, 0)
AS weekend_day_count
FROM range;
Which outputs:
WEEKEND_DAY_COUNT
8
fiddle
One option is to create a calendar between these two dates and then count number of Saturdays and Sundays:
SQL> with
2 test (start_date, end_date) as
3 -- period
4 (select date '2022-12-01', date '2022-12-29' from dual),
5 calendar as
6 -- calendar (all dates between START_DATE and END_DATE)
7 (select start_date + level - 1 as datum
8 from test
9 connect by level <= end_date - start_date + 1
10 )
11 -- number of Saturdays and Sundays
12 select count(*)
13 from calendar
14 where to_char(datum, 'dy', 'nls_date_language = english') in ('sat', 'sun');
COUNT(*)
----------
8
SQL>
You'd change dates at line #4.
P.S. If you look at code MT0 posted and their objection that row generator is inefficient, that's true. Although both queries return the same result, timing is different. For example:
Period 01.01.2022 - 31.12.2022 01.01.1900 - 31.12.2022 01.01.0001 - 31.12.2022
------ ----------------------- ----------------------- -----------------------
LF 00:00:00.00 00:00:00.17 00:00:03.72
MT0 00:00:00.02 00:00:00.02 00:00:00.05
It is obvious that my timing gets worse with period length. If you're looking at one year or a century, the difference is mostly irrelevant. For 2000 years, the difference is huge!
However, if you consider debugging, from my own point of view, my code is easier to read: "select number of rows from the calendar where date is either saturday or sunday" - plain English.
On the other hand, the other code isn't that straightforward; truncate date to week, subtract them, multiply by 2/7 (why "2/7" and not 4/9?), add result returned by the GREATEST function minus 4 (why 4? Why not 7?), subtract GREATEST of something minus 5 (why 5? Why not 2?) - as I said, that's NOT easy to read nor understand.
Therefore, it depends on what you actually need, timing vs. readability. Pick one :)
How can I get the average of the 4 most recent weeks of data in Oracle? The current week is not included, as it's an incomplete week
Assume that for each of the dates (column name: DATEFILED), we have a certain number of vouchers filed. Say we have this data over a period of several weeks, and you want the weekly average of the voucher count over the past 4 complete weeks
This is the query I came up with. I am wondering if anyone has a better solution for this
WITH cteFOURWEEKPERIOD AS
(SELECT NEXT_DAY (SYSDATE - 28, 'SAT') AS BEGINNING_SUNDAY,
NEXT_DAY (SYSDATE - 7, 'SUN') AS ENDING_SATURDAY
FROM DUAL)
SELECT (COUNT(VOUCHERS))/4 AS AVG_COUNT, SYSDATE AS "AS OF"
FROM CLAIMS C
CROSS JOIN cteFOURWEEKPERIOD F
WHERE C.DATEFILED BETWEEN F.BEGINNING_SUNDAY AND F.ENDING_SATURDAY;
This script appears to have worked
WITH cteFOURWEEKPERIOD AS
(SELECT NEXT_DAY (SYSDATE - 28, 'SAT') AS BEGINNING_SUNDAY,
NEXT_DAY (SYSDATE - 7, 'SUN') AS ENDING_SATURDAY
FROM DUAL)
SELECT (COUNT(VOUCHERS))/4 AS AVG_COUNT, SYSDATE AS "AS OF"
FROM CLAIMS C
CROSS JOIN cteFOURWEEKPERIOD F
WHERE C.DATEFILED BETWEEN F.BEGINNING_SUNDAY AND F.ENDING_SATURDAY;
how can i return records sales from todays + 6 months.
Example:
Today´s month: May-2018.
Today´s month + 6: Nov-2018
So, i want a function to retrieve records from Table_Date, from November (1 to 30).
Thanks.
Use the TRUNC and ADD_MONTHS functions:
SELECT *
FROM sales
WHERE SalesDate >= ADD_MONTHS( TRUNC( SYSDATE, 'MM' ), 6 )
AND SalesDate < ADD_MONTHS( TRUNC( SYSDATE, 'MM' ), 7 );
You have SQL server and oracle, it cant be both.
This is for SQL Server (though logic would work in ORACLE, but syntax may not)
This is to get 6 months from today
SELECT DATEADD(MM, 6, GETDATE())
Added extra code here for more details after looking at question more:
I am using variables to do the calculations to make it easier to understand but you could do it all inline (but harder to read).
This script gets a date 6 months from now, takes that month and finds the first day of that month, and then the last day of that month so you can use those 2 dates in a where clause logic.
DECLARE #NewMonth AS VARCHAR(10)
DECLARE #NewYear AS VARCHAR(10) -- in case adding months goes to next year
SELECT #NewMonth = DATEPART(MONTH, DATEADD(MM, 6, GETDATE())),
#NewYear = DATEPART(YEAR, DATEADD(MM, 6, GETDATE()))
DECLARE #FirstOfMonth AS DATE = #NewMonth + '/1/' + #NewYear
-- for start of month check we can just hard code one in it, for end of month we cant because we dont know how many days are in it
SELECT #FirstOfMonth, DATEADD(DAY, -1, DATEADD(MONTH, 1, #FirstOfMonth)) AS LastDayOfMontbh
I group my table by months
SELECT TO_CHAR (created, 'YYYY-MM') AS operation, COUNT (id)
FROM user_info
WHERE created IS NOT NULL
GROUP BY ROLLUP (TO_CHAR (created, 'YYYY-MM'))
2015-04 1
2015-06 10
2015-08 22
2015-09 8
2015-10 13
2015-12 5
2016-01 25
2016-02 37
2016-03 24
2016-04 1
2016-05 1
2016-06 2
2016-08 2
2016-09 7
2016-10 103
2016-11 5
2016-12 2
2017-04 14
2017-05 2
284
But the records don't cover all the months.
I would like the output to include all the months, with the missing ones displayed in the output with a default value:
2017-01 ...
2017-02 ...
2017-03 ZERO
2017-04 ZERO
2017-05 ...
Oracle has a good array of date manipulation functions. The two pertinent ones for this problem are
MONTHS_BETWEEN() which calculates the number of months between two dates
ADD_MONTHS() which increments a date by the given number of months
We can combine these functions to generate a table of all the months spanned by your table's records. Then we use an outer join to conditionally join records from USER_INFO to that calendar. When no records match count(id) will be zero.
with cte as (
select max(trunc(created, 'MM')) as max_dt
, min(trunc(created, 'MM')) as min_dt
from user_info
)
, cal as (
select add_months(min_dt, (level-1)) as mth
from cte
connect by level <= months_between(max_dt, min_dt) + 1
)
select to_char(cal.mth, 'YYYY-MM') as operation
, count(id)
from cal
left outer join user_info
on trunc(user_info.created, 'mm') = cal.mth
group by rollup (cal.mth)
order by 1
/
I have a date field
DATE = 10/10/2010
sum = 4 (this are number of years by calculation)
is there a way to add four years to 10/10/2010 and make it
10/10/2014?
Try adding months (12 * number of years) instead. Like this-
add_months(date'2010-10-10', 48)
Use add_months
Example:
SELECT add_months( to_date('10-OCT-2010'), 48 ) FROM DUAL;
Warning
add_months, returns the last day of the resulting month if you input the last day of a month to begin with.
So add_months(to_date('28-feb-2011'),12) will return 29-feb-2012 as a result.
I believe you could use the ADD_MONTHS() function. 4 years is 48 months, so:
add_months(DATE,48)
Here is some information on using the function:
http://www.techonthenet.com/oracle/functions/add_months.php
http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:1157035034361
You can try this:
someDate + interval '4' year
INTERVAL
I am not sure, if I understood Your question correctly, but
select add_months(someDate, numberOfYears * 12) from dual
might do the trick
One more option apart from ADD_MONTHS
SELECT
SYSDATE,
SYSDATE
+ TO_YMINTERVAL ( '1-0' )
FROM
DUAL;
SYSDATE SYSDATE+TO_YMINTERVAL('1-0')
--------- ----------------------------
29-OCT-13 29-OCT-14
1 row selected.
SELECT
SYSDATE,
SYSDATE
+ TO_YMINTERVAL ( '2-0' )
FROM
DUAL;
SYSDATE SYSDATE+TO_YMINTERVAL('2-0')
--------- ----------------------------
29-OCT-13 29-OCT-15
1 row selected.
SELECT
TO_DATE ( '29-FEB-2004',
'DD-MON-YYYY' )
+ TO_YMINTERVAL ( '1-0' )
FROM
DUAL
*
Error at line 4
ORA-01839: date not valid for month specified
But the last one is illegal since there is no 29th day of February in 2005, hence it fails on leap year cases (Feb 29)
Read the documentation for the same
SELECT TO_CHAR(SYSDATE,'YYYY')-2 ANO FROM DUAL