Optimize SQL query plan Informix - informix

create view "informix".v_prod_cost (ship_no,dc_id,whse_id,cust_id,prod_id,
unit_cost_excl,unit_cost_incl,vat_perc,is_catch_wght,tot_cost_excl,tot_cost_incl) as
SELECT x3.ship_no, x1.dc_id, x1.whse_id, x4.cust_id, x1.prod_id,
x5.case_cost, round(((x5.case_cost * (x7.cvat_desc ::smallint
+ 100. ) ) / 100.0000000000000000 ) , 2 ), x7.cvat_desc,
CASE WHEN ((x4.catch_wgt_ctl = 'Y' ) AND (x5.catch_wgt_cntl
= 'Y' ) ) THEN 'Y' WHEN ((x4.catch_wgt_ctl = 'N' ) AND (x5.catch_wgt_cntl
= 'Y' ) ) THEN 'N' ELSE 'N' END,
CASE WHEN ((x4.catch_wgt_ctl
= 'Y' ) AND (x5.catch_wgt_cntl = 'Y' ) ) THEN round(sum((select
(sum(x9.catch_wgt ) * x5.case_cost ) from "informix".icwma
x8 ,"informix".icwmad x9 where (((((((((((x8.cwma_id = x9.cwma_id
) AND (x8.dc_id = x1.dc_id ) ) AND (x8.whse_id = x1.whse_id
) ) AND (x8.curr_pal_no = x1.curr_pal_no ) ) AND (x8.ord_id
= x1.ord_id ) ) AND (x8.prod_id = x1.prod_id ) ) AND (x8.invc_id
= x1.invc_id ) ) AND (x8.sgmt_id = x1.sgmt_id ) ) AND (x8.unit_ship_cse
= x1.unit_ship_cse ) ) AND (x8.assg_id = x1.assg_id ) ) AND
(x8.ckpt_id = x1.ckpt_id ) ) ) ) , 2 ) WHEN ((x4.catch_wgt_ctl
= 'N' ) AND (x5.catch_wgt_cntl = 'Y' ) ) THEN round(sum((((x1.prod_qty
/ x1.unit_ship_cse ) * x1.prod_wgt ) * x5.case_cost ) ) ,
2 ) ELSE round(sum((x1.prod_qty * x5.case_cost ) ) , 2
) END,
CASE WHEN ((x4.catch_wgt_ctl = 'Y' ) AND (x5.catch_wgt_cntl
= 'Y' ) ) THEN round(sum((select (((sum(x11.catch_wgt ) *
x5.case_cost ) * (x7.cvat_desc ::smallint + 100. ) ) / 100.0000000000000000
) from "informix".icwma x10 ,"informix".icwmad x11 where (((((((((((x10.cwma_id
= x11.cwma_id ) AND (x10.dc_id = x1.dc_id ) ) AND (x10.whse_id
= x1.whse_id ) ) AND (x10.curr_pal_no = x1.curr_pal_no )
) AND (x10.ord_id = x1.ord_id ) ) AND (x10.prod_id = x1.prod_id
) ) AND (x10.invc_id = x1.invc_id ) ) AND (x10.sgmt_id =
x1.sgmt_id ) ) AND (x10.unit_ship_cse = x1.unit_ship_cse
) ) AND (x10.assg_id = x1.assg_id ) ) AND (x10.ckpt_id =
x1.ckpt_id ) ) ) ) , 2 ) WHEN ((x4.catch_wgt_ctl = 'N' )
AND (x5.catch_wgt_cntl = 'Y' ) ) THEN round(sum(((((x1.prod_qty
/ x1.unit_ship_cse ) * x1.prod_wgt ) * x5.case_cost ) * (x7.cvat_desc
::smallint + 100. ) ) ) , 2 ) ELSE round(sum((((x1.prod_qty
* x5.case_cost ) * (x7.cvat_desc ::smallint + 100. ) ) /
100.0000000000000000 ) ) , 2 ) END
FROM "informix".ishs x0,
"informix".ishd x1, "informix".irtst x2, "informix".crtst x3,
"informix".icust x4, "informix".iprod x5, "informix".cprod x6,
"informix".cvat x7
WHERE ((((((((((((x0.shs_id = x1.shs_id
) AND (x0.dc_id = x1.dc_id ) ) AND (x0.whse_id = x1.dc_id
) ) AND (x0.rtst_id = x2.rtst_id ) ) AND (x0.dc_id = x2.dc_id
) ) AND (x1.whse_id = x2.dc_id ) ) AND (x2.rtst_id = x3.rtst_id
) ) AND (x1.cust_id = x4.cust_id ) ) AND (x1.dc_id = x5.dc_id
) ) AND (x1.prod_id = x5.prod_id ) ) AND (x5.prod_id = x6.prod_id
) ) AND (x6.vat_ind = x7.vat_ind ) )
GROUP BY x3.ship_no, x1.dc_id, x1.whse_id, x4.cust_id, x1.prod_id,
x5.case_cost, 7, x7.cvat_desc, 9, x4.catch_wgt_ctl, x5.catch_wgt_cntl
;
I have the view above, which was created to perform the necessary calculations. The problem I am facing it takes over 5 minutes to run.
This is my sql trace output:
IBM Informix Dynamic Server Version 12.10.FC4W1WE -- On-Line -- Up 27 days 20:42:31 -- 2211344 Kbytes
Statement history:
Trace Level High
Trace Mode User
Number of traces 1000
Current Stmt ID 1
Trace Buffer size 4056
Duration of buffer 1481025737 Seconds
Trace Flags 0x0000FF21
Control Block 700000015dc1028
Statement # 1: # 700000015dc1048
Database: system
Statement text:
select * from v_prod_cost
SELECT using tables [ ishs ishd irtst crtst icust iprod cprod cvat ]
Iterator/Explain
================
ID Left Right Sender Next Est Cost Est Rows Num Rows Partnum Type
9 0 0 0 0 10054 47203 47203 7342066 Seq Scan
10 0 0 0 0 1 40977 1 7340184 Index Scan
8 9 10 0 0 35212 40977 40715 0 Nested Join
11 0 0 0 0 2 325474 6 7343766 Index Scan
7 8 11 0 0 154765 278608 303217 0 Nested Join
12 0 0 0 0 1 1280461 1 7343819 Index Scan
6 7 12 0 0 550996 1111035 1225518 0 Nested Join
13 0 0 0 0 1 152406 1 7340237 Index Scan
5 6 13 0 0 1337728 1111035 1225518 0 Nested Join
14 0 0 0 0 2 2 2 7340235 Seq Scan
4 5 14 0 0 1544660 1111032 1225518 0 Hash Join
15 0 0 0 0 1 6941 1 7343796 Index Scan
3 4 15 0 0 2084251 1111036 1225518 0 Nested Join
16 0 0 0 0 1 152627 1 7341873 Index Scan
2 3 16 0 0 3736185 1109418 1225518 0 Nested Join
1 2 0 0 0 2892742 1108253 27 0 Group
Statement information:
Sess_id User_id Stmt Type Finish Time Run Time TX Stamp PDQ
207705 55121 SELECT 14:02:16 99.8398 cd5d6ee8 0
Statement Statistics:
Page Buffer Read Buffer Page Buffer Write
Read Read % Cache IDX Read Write Write % Cache
0 18720195 100.00 0 87400 704 0.00
Lock Lock LK Wait Log Num Disk Memory
Requests Waits Time (S) Space Sorts Sorts Sorts
10561863 0 0.0000 0.000 B 0 0 0
Total Total Avg Max Avg I/O Wait Avg Rows
Executions Time (S) Time (S) Time (S) IO Wait Time (S) Per Sec
1 99.8398 99.8398 99.8398 0.000000 0.000000 0.2704
Estimated Estimated Actual SQL ISAM Isolation SQL
Cost Rows Rows Error Error Level Memory
6628928 1108253 27 0 0 CR 331184
The below is my SET EXPLAIN output:
QUERY: (OPTIMIZATION TIMESTAMP: 12-06-2016 14:12:43)
------
select * from v_prod_cost
Estimated Cost: 6628928
Estimated # of Rows Returned: 1108253
Temporary Files Required For: Group By
1) informix.irtst: SEQUENTIAL SCAN
2) informix.crtst: INDEX PATH
(1) Index Name: informix. 1565_316639
Index Keys: rtst_id (Serial, fragments: ALL)
Lower Index Filter: informix.irtst.rtst_id = informix.crtst.rtst_id
NESTED LOOP JOIN
3) informix.ishs: INDEX PATH
Filters: (informix.ishs.dc_id = informix.irtst.dc_id AND informix.ishs.dc_id = informix.ishs.whse_id )
(1) Index Name: informix.ishs_rtst
Index Keys: rtst_id (Serial, fragments: ALL)
Lower Index Filter: informix.ishs.rtst_id = informix.crtst.rtst_id
NESTED LOOP JOIN
4) informix.ishd: INDEX PATH
Filters: (informix.ishs.whse_id = informix.ishd.dc_id AND informix.ishd.dc_id = informix.ishd.whse_id )
(1) Index Name: informix.ishdd1
Index Keys: shs_id (Serial, fragments: ALL)
Lower Index Filter: informix.ishs.shs_id = informix.ishd.shs_id
NESTED LOOP JOIN
5) informix.cprod: INDEX PATH
(1) Index Name: informix.cprodu1
Index Keys: prod_id (Serial, fragments: ALL)
Lower Index Filter: informix.ishd.prod_id = informix.cprod.prod_id
NESTED LOOP JOIN
6) informix.cvat: SEQUENTIAL SCAN
DYNAMIC HASH JOIN
Dynamic Hash Filters: informix.cprod.vat_ind = informix.cvat.vat_ind
7) informix.icust: INDEX PATH
(1) Index Name: informix.icustu1
Index Keys: cust_id (Serial, fragments: ALL)
Lower Index Filter: informix.ishd.cust_id = informix.icust.cust_id
NESTED LOOP JOIN
8) informix.iprod: INDEX PATH
(1) Index Name: informix. 588_2002
Index Keys: prod_id dc_id (Serial, fragments: ALL)
Lower Index Filter: (informix.iprod.prod_id = informix.cprod.prod_id AND informix.ishs.whse_id = informix.iprod.dc_id )
NESTED LOOP JOIN
Query statistics:
-----------------
Table map :
----------------------------
Internal name Table name
----------------------------
t1 irtst
t2 crtst
t3 ishs
t4 ishd
t5 cprod
t6 cvat
t7 icust
t8 iprod
type table rows_prod est_rows rows_scan time est_cost
-------------------------------------------------------------------
scan t1 47203 47203 47203 00:00.10 10054
type table rows_prod est_rows rows_scan time est_cost
-------------------------------------------------------------------
scan t2 40715 40977 40715 00:00.41 1
type rows_prod est_rows time est_cost
-------------------------------------------------
nljoin 40715 40978 00:00.53 35213
type table rows_prod est_rows rows_scan time est_cost
-------------------------------------------------------------------
scan t3 303217 325474 303217 00:01.35 3
type rows_prod est_rows time est_cost
-------------------------------------------------
nljoin 303217 278609 00:01.94 154765
type table rows_prod est_rows rows_scan time est_cost
-------------------------------------------------------------------
scan t4 1225518 1280461 1225518 00:07.02 1
type rows_prod est_rows time est_cost
-------------------------------------------------
nljoin 1225518 1111035 00:09.22 550996
type table rows_prod est_rows rows_scan time est_cost
-------------------------------------------------------------------
scan t5 1225518 152406 1225518 00:11.75 1
type rows_prod est_rows time est_cost
-------------------------------------------------
nljoin 1225518 1111036 00:21.40 1337728
type table rows_prod est_rows rows_scan time est_cost
-------------------------------------------------------------------
scan t6 2 2 2 00:00.00 2
type rows_prod est_rows rows_bld rows_prb novrflo time est_cost
------------------------------------------------------------------------------
hjoin 1225518 1111033 2 1225518 0 00:25.94 1544661
type table rows_prod est_rows rows_scan time est_cost
-------------------------------------------------------------------
scan t7 1225518 6941 1225518 00:09.50 0
type rows_prod est_rows time est_cost
-------------------------------------------------
nljoin 1225518 1111037 00:35.99 2084251
type table rows_prod est_rows rows_scan time est_cost
-------------------------------------------------------------------
scan t8 1225518 152627 1225518 00:12.24 1
type rows_prod est_rows time est_cost
-------------------------------------------------
nljoin 1225518 1109418 00:48.97 3736186
type rows_prod est_rows rows_cons time est_cost
------------------------------------------------------------
group 27 1108253 1225518 01:42.95 2892742
What can I do to reduce the cost of nested loops and dynamics hash joins?

Related

How can I aggregated 3 measures in a line chart by an assigned day number, not date, in Tableau?

I can't figure out how to attach the .csv or workbook. Can someone explain?
I feel like I am overcomplicating this. I have a simple line chart, comparing 2 SUM values, in 3 measures, across an assigned day number. I've attached a .csv with sample data & tableau wbk. If I need to provide anything else, please let me know.
The viz also needs to by dynamic, so they can toggle between months past using a parameter [Selected Month] to toggle between months; in this example September is selected.
The [Contributing Day#] number is a field in the data provided by the user, not a calculation. I cannot use the workday feature, because weekend dates and holidays are sometimes considered a [Contributing Day#].
A date is matched to a Contributing_Day#. I can't compare date to date, they want to see it across Contributing_Day# instead.
I need to aggregate daily for the smaller number of days; in this example I would want to exclude Contributing_Day# 6 & 7 from the viz since one month only went to 5.
It needs to be MTD minus today, meaning if only Contributing_Day# <= 4 has passed, all 3 measures would null after Contributing_Day# 4
And if that wasn't enough, I need to exclude a dimension [Role] = 'Role' string type as well.
Measure_1 = SUM(Value_Sum) for [Selected Month]
Measure_2 = SUM(Value_Sum) for [Selected Month] - 1
Measure_3 = SUM(Value_Goal) for [Selected Month]
September Date | [Contributing_Day#] | Measure_1 | Measure_3
9/1/22 | 1 | 105 | 96
9/2/22 | 2 | 112 | 92
9/6/22 | 3 | 129 | 99
9/7/22 | 4 | 108 | 100
9/8/22 | 5 | 108 | 98
August Date | [Contributing_Day#] | Measure_2
8/1/22 | 1 | 105
8/2/22 | 2 | 112
8/3/22 | 3 | 129
8/4/22 | 4 | 108
8/5/22 | 5 | 108
8/8/22 | 6 | 112
8/9/22 | 7 | 92
Here is what I have tried that was almost working but not, and a screen shot of my visual when I have September selected and October.
Measure_1
{Fixed [Date],[Role] :SUM(IF MONTH([Date]) = MONTH(TODAY())AND DAY ([Date]) < DAY(TODAY())AND
[Role] <> 'Role' THEN [Value_1] END) }
Measure_2
{Fixed [Date],[Role] :
SUM(
IF ISNULL([Measure_1]) THEN NULL
ELSEIF MONTH([Date]) = MONTH(TODAY())-1
AND DAY ([Date]) < DAY(TODAY())
AND [Role] <> 'Role'
THEN [Value_1] END) }
Measure_3
{Fixed [Date],[Role] :
SUM(
IF MONTH([Date]) = MONTH(TODAY())
AND DAY ([Date]) < DAY(TODAY())
AND [Role] <> 'Role'
THEN [Value_2] END) }
Other calculations I've tried...
SUM(
{ FIXED [Date] :
MAX(IF DATEPART('year',[Date]) = DATEPART('year',[Select Month])
AND DATEPART('month',[Date]) <= DATEPART('month',[Select Month])
AND [Contributing_Day#] = 1
THEN 1 ELSE NULL END)
})
COUNTD(IF DATEPART('year',[Date]) = DATEPART('year',[Select Month])
AND [Contributing_Day#] = 1
THEN [Date] ELSE NULL END)
[% of Month Complete]
would be count of [Contributing_Day#] past / total count of [Contributing_Day#]
But I haven't been able to get that to work
[Role Flag]
{Fixed [Date],[Role] :
SUM(IF [Role] <> 'Role' THEN 0 ELSE 1 END) }
Measure_1
{Fixed [Date],[Role] : IF [% of Month Complete] = 1 THEN
SUM([Value_1]) ELSEIF MAX(MONTH([Date])) = MAX(MONTH([Select Month]))
AND MAX(DAY([Date])) < MAX(DAY([Select Month])) AND MAX([Role Flag])
<> 1 THEN SUM([Value_1]) END }
Measure_2
{Fixed [Date],[Role] :
IF MAX([Measure_1]) = 0 THEN NULL
ELSEIF [% of Month Complete] = 1
AND MAX(MONTH([Date])) = MAX(MONTH([Select Month]))-1
AND MAX([Role Flag]) <> 1
THEN SUM([Value_1])
ELSEIF MAX(MONTH([Date])) = MAX(MONTH([Select Month]))-1
AND MAX(DAY([Date])) < MAX(DAY([Select Month]))
AND MAX([Role Flag]) <> 1
THEN SUM([Value_1]) END }

Why ChunkSpy .function part has four parameters?

When using ChunkSpy, I find one thing makes me coufused. Let's see the following example
>a = 1
; source chunk: (interactive mode)
; x86 standard (32-bit, little endian, doubles)
; function [0] definition (level 1)
; 0 upvalues, 0 params, 2 stacks
.function 0 0 2 2
.const "a" ; 0
.const 1 ; 1
[1] loadk 0 1 ; 1
[2] setglobal 0 0 ; a
[3] return 0 1
; end of function
Since here is 0 upvalues, 0 params, 2 stacks, why there are four parameters in .function 0 0 2 2
In another example, we can see that
>local a; function b() a = 1 return a end
; source chunk: (interactive mode)
; x86 standard (32-bit, little endian, doubles)
; function [0] definition (level 1)
; 0 upvalues, 0 params, 2 stacks
.function 0 0 2 2
.local "a" ; 0
.const "b" ; 0
; function [0] definition (level 2)
; 1 upvalues, 0 params, 2 stacks
.function 1 0 0 2
.upvalue "a" ; 0
.const 1 ; 0
[1] loadk 0 0 ; 1
[2] setupval 0 0 ; a
[3] getupval 0 0 ; a
[4] return 0 2
[5] return 0 1
; end of function
[1] closure 1 0 ; 1 upvalues
[2] move 0 0
[3] setglobal 1 0 ; b
[4] return 0 1
; end of function
So I guess the first parameter is upvalues, but what is the use of the second?
I get the answer by the help of Egor Skriptunoff from comments.
The .fucntion part with four parameters are meaning like below:
number of upvales
number of named parameters
flag of arg : 1=VARARG_HASARG, 2=VARARG_ISVARARG, 4=VARARG_NEEDSARG. It's always 0 for normal function, and 2 for main function chunk.
number of stacks

How to join two table with a conditon

TABLO1
Inst_count Inst_Type Card_Group Txn_Type Comm_rate
---------- --------- ---------- -------- ---------
2 N -1 -1 1,70
2 N 36 -1 1,71
2 N 37 -1 1,72
2 V -1 -1 1,73
2 V 36 -1 1,74
2 V 37 -1 1,75
TABLO2
Inst_count Inst_Type Card_Group Txn_Type Isk_rate Day
---------- --------- ---------- -------- -------- ---
2 N -1 -1 1,0 10
2 N 36 -1 1,1 11
2 N 37 -1 1,2 12
2 V -1 -1 1,3 13
2 V 36 -1 1,4 14
2 V 38 -1 1,5 15
Result_Table
Inst_count Inst_Type TABLO1.Card_Group TABLO2.Card_Group TABLO1.Txn_Type TABLO2.Txn_Type Isk_rate Day Comm_rate
---------- --------- ----------------- ----------------- --------------- --------------- -------- --- ---------
2 N -1 -1 -1 -1 1,0 10 1,70
2 N 36 36 -1 -1 1,1 11 1,71
2 N 37 37 -1 -1 1,2 12 1,72
2 V -1 -1 -1 -1 1,3 13 1,73
2 V 36 36 -1 -1 1,4 14 1,74
2 V -1 38 -1 -1 1,5 15 1,73
2 V 37 -1 -1 -1 1,3 13 1,75
Inst_count and Inst_Type must be always equal.
But Card_Group and Txn_Type columns must be match in the other table with default value(-1) if not exist.
How can write this sql?
Thanks.
Here we are using OUTER JOIN which sets all your tables values into one resulset(You can also use UNION ALL for this purpose). Then we are using a left join for each table to make sure each column will have its values which absence of other. Now you can try this with your own query. If you can not achieve your goal then i suggest you to gather your samples into dbfiddle link. Then we can make further explanations.
SELECT DISTINCT NVL (A.COL1, A1.COL1) COL1A,
NVL (B.COL1, B1.COL1) COL1B,
NVL (A.COL2, A1.COL2) COL2,
NVL (A.COL3, A1.COL3) COL3,
NVL (B.COL3, B1.COL3) COL4
FROM TABLEA A
FULL OUTER JOIN TABLEB B ON B.COL1 = A.COL1
LEFT OUTER JOIN TABLEB B1 ON B1.COL1 = -1
LEFT OUTER JOIN TABLEA A1 ON A1.COL1 = -1

how to group a date column based on date range in oracle

I have a table which contains a feedback about a product.It has feedback type (positive ,negative) which is a text column, date on which comments made. I need to get total count of positive ,negative feedback for particular time period . For example if the date range is 30 days, I need to get total count of positive ,negative feedback for 4 weeks , if the date range is 6 months , I need to get total count of positive ,negative feedback for each month. How to group the count based on date.
+------+------+----------+----------+---------------+--+--+--+
| Slno | User | Comments | type | commenteddate | | | |
+------+------+----------+----------+---------------+--+--+--+
| 1 | a | aaaa | positive | 22-jun-2016 | | | |
| 2 | b | bbb | positive | 1-jun-2016 | | | |
| 3 | c | qqq | negative | 2-jun-2016 | | | |
| 4 | d | ccc | neutral | 3-may-2016 | | | |
| 5 | e | www | positive | 2-apr-2016 | | | |
| 6 | f | s | negative | 11-nov-2015 | | | |
+------+------+----------+----------+---------------+--+--+--+
Query i tried is
SELECT type, to_char(commenteddate,'DD-MM-YYYY'), Count(type) FROM comments GROUP BY type, to_char(commenteddate,'DD-MM-YYYY');
Here's a kick at the can...
Assumptions:
you want to be able to switch the groupings to weekly or monthly only
the start of the first period will be the first date in the feedback data; intervals will be calculated from this initial date
output will show feedback value, time period, count
time periods will not overlap so periods will be x -> x + interval - 1 day
time of day is not important (time for commented dates is always 00:00:00)
First, create some sample data (100 rows):
drop table product_feedback purge;
create table product_feedback
as
select rownum as slno
, chr(65 + MOD(rownum, 26)) as userid
, lpad(chr(65 + MOD(rownum, 26)), 5, chr(65 + MOD(rownum, 26))) as comments
, trunc(sysdate) + rownum + trunc(dbms_random.value * 10) as commented_date
, case mod(rownum * TRUNC(dbms_random.value * 10), 3)
when 0 then 'positive'
when 1 then 'negative'
when 2 then 'neutral' end as feedback
from dual
connect by level <= 100
;
Here's what my sample data looks like:
select *
from product_feedback
;
SLNO USERID COMMENTS COMMENTED_DATE FEEDBACK
1 B BBBBB 2016-08-06 neutral
2 C CCCCC 2016-08-06 negative
3 D DDDDD 2016-08-14 positive
4 E EEEEE 2016-08-16 negative
5 F FFFFF 2016-08-09 negative
6 G GGGGG 2016-08-14 positive
7 H HHHHH 2016-08-17 positive
8 I IIIII 2016-08-18 positive
9 J JJJJJ 2016-08-12 positive
10 K KKKKK 2016-08-15 neutral
11 L LLLLL 2016-08-23 neutral
12 M MMMMM 2016-08-19 positive
13 N NNNNN 2016-08-16 neutral
...
Now for the fun part. Here's the gist:
find out what the earliest and latest commented dates are in the data
include a query where you can set the time period (to "WEEKS" or "MONTHS")
generate all of the (weekly or monthly) time periods between the min/max dates
join the product feedback to the time periods (commented date between start and end) with an outer join in case you want to see all time periods whether or not there was any feedback
group the joined result by feedback, period start, and period end, and set up a column to count one of the 3 possible feedback values
x
with
min_max_dates -- get earliest and latest feedback dates
as
(select min(commented_date) min_date, max(commented_date) max_date
from product_feedback
)
, time_period_interval
as
(select 'MONTHS' as tp_interval -- set the interval/time period here
from dual
)
, -- generate all time periods between the start date and end date
time_periods (start_of_period, end_of_period, max_date, time_period) -- recursive with clause - fun stuff!
as
(select mmd.min_date as start_of_period
, CASE WHEN tpi.tp_interval = 'WEEKS'
THEN mmd.min_date + 7
WHEN tpi.tp_interval = 'MONTHS'
THEN ADD_MONTHS(mmd.min_date, 1)
ELSE NULL
END - 1 as end_of_period
, mmd.max_date
, tpi.tp_interval as time_period
from time_period_interval tpi
cross join
min_max_dates mmd
UNION ALL
select CASE WHEN time_period = 'WEEKS'
THEN start_of_period + 7 * (ROWNUM )
WHEN time_period = 'MONTHS'
THEN ADD_MONTHS(start_of_period, ROWNUM)
ELSE NULL
END as start_of_period
, CASE WHEN time_period = 'WEEKS'
THEN start_of_period + 7 * (ROWNUM + 1)
WHEN time_period = 'MONTHS'
THEN ADD_MONTHS(start_of_period, ROWNUM + 1)
ELSE NULL
END - 1 as end_of_period
, max_date
, time_period
from time_periods
where end_of_period <= max_date
)
-- now put it all together
select pf.feedback
, tp.start_of_period
, tp.end_of_period
, count(*) as feedback_count
from time_periods tp
left outer join
product_feedback pf
on pf.commented_date between tp.start_of_period and tp.end_of_period
group by tp.start_of_period
, tp.end_of_period
, pf.feedback
order by pf.feedback
, tp.start_of_period
;
Output:
negative 2016-08-06 2016-09-05 6
negative 2016-09-06 2016-10-05 7
negative 2016-10-06 2016-11-05 8
negative 2016-11-06 2016-12-05 1
neutral 2016-08-06 2016-09-05 6
neutral 2016-09-06 2016-10-05 5
neutral 2016-10-06 2016-11-05 11
neutral 2016-11-06 2016-12-05 2
positive 2016-08-06 2016-09-05 17
positive 2016-09-06 2016-10-05 16
positive 2016-10-06 2016-11-05 15
positive 2016-11-06 2016-12-05 6
-- EDIT --
New and improved, all in one easy to use procedure. (I will assume you can configure the procedure to make use of the query in whatever way you need.) I made some changes to simplify the CASE statements in a few places and note that for whatever reason using a LEFT OUTER JOIN in the main SELECT results in an ORA-600 error for me so I switched it to INNER JOIN.
CREATE OR REPLACE PROCEDURE feedback_counts(p_days_chosen IN NUMBER, p_cursor OUT SYS_REFCURSOR)
AS
BEGIN
OPEN p_cursor FOR
with
min_max_dates -- get earliest and latest feedback dates
as
(select min(commented_date) min_date, max(commented_date) max_date
from product_feedback
)
, time_period_interval
as
(select CASE
WHEN p_days_chosen BETWEEN 1 AND 10 THEN 'DAYS'
WHEN p_days_chosen > 10 AND p_days_chosen <=31 THEN 'WEEKS'
WHEN p_days_chosen > 31 AND p_days_chosen <= 365 THEN 'MONTHS'
ELSE '3-MONTHS'
END as tp_interval -- set the interval/time period here
from dual --(SELECT p_days_chosen as days_chosen from dual)
)
, -- generate all time periods between the start date and end date
time_periods (start_of_period, end_of_period, max_date, tp_interval) -- recursive with clause - fun stuff!
as
(select mmd.min_date as start_of_period
, CASE tpi.tp_interval
WHEN 'DAYS'
THEN mmd.min_date + 1
WHEN 'WEEKS'
THEN mmd.min_date + 7
WHEN 'MONTHS'
THEN mmd.min_date + 30
WHEN '3-MONTHS'
THEN mmd.min_date + 90
ELSE NULL
END - 1 as end_of_period
, mmd.max_date
, tpi.tp_interval
from time_period_interval tpi
cross join
min_max_dates mmd
UNION ALL
select CASE tp_interval
WHEN 'DAYS'
THEN start_of_period + 1 * ROWNUM
WHEN 'WEEKS'
THEN start_of_period + 7 * ROWNUM
WHEN 'MONTHS'
THEN start_of_period + 30 * ROWNUM
WHEN '3-MONTHS'
THEN start_of_period + 90 * ROWNUM
ELSE NULL
END as start_of_period
, start_of_period
+ CASE tp_interval
WHEN 'DAYS'
THEN 1
WHEN 'WEEKS'
THEN 7
WHEN 'MONTHS'
THEN 30
WHEN '3-MONTHS'
THEN 90
ELSE NULL
END * (ROWNUM + 1)
- 1 as end_of_period
, max_date
, tp_interval
from time_periods
where end_of_period <= max_date
)
-- now put it all together
select pf.feedback
, tp.start_of_period
, tp.end_of_period
, count(*) as feedback_count
from time_periods tp
inner join -- currently a bug that prevents the procedure from compiling with a LEFT OUTER JOIN
product_feedback pf
on pf.commented_date between tp.start_of_period and tp.end_of_period
group by tp.start_of_period
, tp.end_of_period
, pf.feedback
order by tp.start_of_period
, pf.feedback
;
END;
Test the procedure (in something like SQLPlus or SQL Developer):
var x refcursor
exec feedback_counts(10, :x)
print :x

IBM DB2 SQLCODE -1424, SQLSTATE 54040 when trying to create a trigger

I have tried to create the following trigger (DB2/LINUXX8664 9.7.2 running over Ubuntu 10.04.2 LTS) but I always get this:
Error report:
DB2 SQL error: SQLCODE: -1424, SQLSTATE: 54040, SQLERRMC: 2
According IBM DB2 documentation:
Too many references to transition variables and transition table columns or the row length for these references is too long. Reason code=rc.
http://www-01.ibm.com/support/knowledgecenter/SSEPGG_9.5.0/com.ibm.db2.luw.messages.sql.doc/doc/msql01424n.html
I really do not understand that explanation. Here the stored procedure and trigger:
CREATE PROCEDURE SP_INSERT_UPDATE_REPNUM (
IN RECNUM INTEGER,
IN CUSTOMER_ID INTEGER,
IN Q_CODE VARCHAR(14),
IN S_CODE VARCHAR(14),
IN REP_STATUS INTEGER,
IN P_CODE INTEGER,
IN REPNUMRG_ID INTEGER,
IN VOLG_LET VARCHAR(1),
IN REP_DATUM DATE,
IN REP_INI VARCHAR(2),
IN INGEBOEKT_DATUM DATE,
IN INGEBOEKT_INI VARCHAR(2),
IN WIJZIGING_DATUM DATE,
IN WIJZIGING_INI VARCHAR(2),
IN OMSCR_STORING VARCHAR(5),
IN OMSCR_WERKZ VARCHAR(5),
IN OMSCR_OPMERKING VARCHAR(5),
IN OMSCR_GEBREK VARCHAR(5),
IN OMSCR_MAT VARCHAR(5),
IN REP_TIJD FLOAT,
IN REP_GEDAAN CHAR(1),
IN ACTION CHAR(1)
)
SPECIFIC SP_INSERT_UPDATE_REPNUM
DYNAMIC RESULT SETS 0
DETERMINISTIC
LANGUAGE JAVA
PARAMETER STYLE JAVA
NO DBINFO
NOT FENCED
THREADSAFE
MODIFIES SQL DATA
PROGRAM TYPE SUB
EXTERNAL NAME 'RepairMigration!insertServiceReport'
and here the trigger:
CREATE TRIGGER INSERT_REPNUM
AFTER INSERT ON REPNUM
REFERENCING NEW ROW AS NROW
FOR EACH ROW MODE DB2SQL
BEGIN
CALL SP_INSERT_UPDATE_REPNUM(
NROW.RECNUM,
NROW.CUSTOMER_ID,
NROW.Q_CODE,
NROW.S_CODE,
NROW.REP_STATUS,
NROW.P_CODE,
NROW.REPNUMRG_ID,
NROW.VOLG_LET,
NROW.REP_DATUM,
NROW.REP_INI,
NROW.INGEBOEKT_DATUM,
NROW.INGEBOEKT_INI,
NROW.WIJZIGING_DATUM,
NROW.WIJZIGING_INI,
NROW.OMSCR_STORING,
NROW.OMSCR_WERKZ,
NROW.OMSCR_OPMERKING,
NROW.OMSCR_GEBREK,
NROW.OMSCR_MAT,
NROW.REP_TIJD,
NROW.REP_GEDAAN,
'I'
);
END
the table structure is thsi one:
RECNUM INTEGER 4 0 N
Q_CODE CHARACTER 14 0 N ''
U_Q_CODE CHARACTER 14 0 N
S_CODE CHARACTER 14 0 N ''
U_S_CODE CHARACTER 14 0 N
VOLG_LET CHARACTER 1 0 N ''
U_VOLG_LET CHARACTER 1 0 N
REP_DATUM DATE 4 0 N '0001-01-01'
REP_INI CHARACTER 2 0 N ''
P_CODE INTEGER 4 0 N 0
CUSTOMER_ID INTEGER 4 0 N 0
REPNUMHD_ID INTEGER 4 0 N 0
REPNUMRG_ID INTEGER 4 0 N 0
REP_STATUS SMALLINT 2 0 N 0
KONTAKT_PER CHARACTER 25 0 N ''
KONTAKT_TEL CHARACTER 20 0 N ''
OMSCR_STORING VARCHAR 512 0 N ''
OMSCR_WERKZ VARCHAR 2000 0 N ''
OMSCR_MAT VARCHAR 512 0 N ''
WIJZIGING_DATUM DATE 4 0 N '0001-01-01'
WIJZIGING_INI CHARACTER 2 0 N ''
INGEBOEKT_DATUM DATE 4 0 N '0001-01-01'
INGEBOEKT_INI CHARACTER 2 0 N ''
REP_GEDAAN CHARACTER 1 0 N ''
U_REP_GEDAAN CHARACTER 1 0 N
STATUS SMALLINT 2 0 N 0
UW_OPDRACHT CHARACTER 20 0 N ''
REP_UREN SMALLINT 2 0 N 0
REP_MINUTEN SMALLINT 2 0 N 0
OMSCR_OPMERKING VARCHAR 1008 0 N ''
OMSCR_GEBREK VARCHAR 512 0 N ''
SERVICE_NUMMER INTEGER 4 0 N 0
PRIJS_OPGAVE CHARACTER 1 0 N ''
CURRENCY SMALLINT 2 0 N 0
REP_TIJD INTEGER 4 0 N 0
After trying to execute the trigger, I get the error. How can I solve this?
UPDATE
It looks that I need to create a temporary tablespace. Listing all my tablespaces, I got some with more than 4k, for example this one:
Tablespace ID = 7
Name = TEMPSPACE1234
Type = Database managed space
Contents = All permanent data. Regular table space.
State = 0x0000
Detailed explanation:
Normal
Total pages = 1024
Useable pages = 1008
Used pages = 432
Free pages = 576
High water mark (pages) = 528
Page size (bytes) = 32768
Extent size (pages) = 16
Prefetch size (pages) = 16
Number of containers = 1
1) Create a 32K Buffer Pool
Example:
CREATE BUFFERPOOL "BUFFERPOOLLARGE" IMMEDIATE
ALL DBPARTITIONNUMS SIZE AUTOMATIC
NUMBLOCKPAGES 0
PAGESIZE 32 K;
2) Create a 32K SYSTEM TEMPORARY TABLESPACE
Example:
CREATE SYSTEM TEMPORARY TABLESPACE "TEMPSPACELARGE"
IN DATABASE PARTITION GROUP "IBMTEMPGROUP"
PAGESIZE 32 K
MANAGED BY AUTOMATIC STORAGE
EXTENTSIZE 32
BUFFERPOOL "BUFFERPOOLLARGE"
OVERHEAD INHERIT
TRANSFERRATE INHERIT
USING STOGROUP "IBMSTOGROUP"
FILE SYSTEM CACHING;
3) Run CREATE PROCEDURE Script Again.
OBS:In the examples I used DB2 automatic TABLESPACE.

Resources