I'm trying to display how many cages for each rate and the start and end date. This is going into an invoice where we bill for each cage per day and these cages can have different rates.
It isn't a simple GROUP BY and getting the MIN and MAX dates since the number of cages can go down or up and then back to the same number again so I need to only look at contiguous data.
I searched for a solution and found this answer. I modified it a little bit to suit my needs and came up with this:
WITH cte(rate_name, cages, use_date) AS (
SELECT 'I1', 8, DATE'2017-11-04' FROM DUAL UNION ALL
SELECT 'I1', 8, DATE'2017-11-05' FROM DUAL UNION ALL
SELECT 'I1', 7, DATE'2017-11-07' FROM DUAL UNION ALL
SELECT 'I1', 7, DATE'2017-11-10' FROM DUAL UNION ALL
SELECT 'I1', 7, DATE'2017-11-11' FROM DUAL UNION ALL
SELECT 'I1', 8, DATE'2017-11-12' FROM DUAL UNION ALL
SELECT 'I1', 8, DATE'2017-11-13' FROM DUAL UNION ALL
SELECT 'I1', 8, DATE'2017-11-14' FROM DUAL UNION ALL
SELECT 'I1 - BR', 5, DATE'2017-11-01' FROM DUAL UNION ALL
SELECT 'I1 - BR', 5, DATE'2017-11-02' FROM DUAL UNION ALL
SELECT 'I1 - BR', 5, DATE'2017-11-03' FROM DUAL UNION ALL
SELECT 'I1 - BR', 5, DATE'2017-11-04' FROM DUAL UNION ALL
SELECT 'I1 - BR', 5, DATE'2017-11-05' FROM DUAL UNION ALL
SELECT 'I1 - BR', 1, DATE'2017-11-06' FROM DUAL UNION ALL
SELECT 'I1 - BR', 1, DATE'2017-11-07' FROM DUAL UNION ALL
SELECT 'I1 - BR', 1, DATE'2017-11-08' FROM DUAL UNION ALL
SELECT 'I1 - BR', 5, DATE'2017-11-09' FROM DUAL UNION ALL
SELECT 'I1 - BR', 5, DATE'2017-11-10' FROM DUAL UNION ALL
SELECT 'I1 - BR', 5, DATE'2017-11-11' FROM DUAL
)
SELECT
a.rate_name,
a.cages,
MIN(a.use_date) AS startdate,
MAX(a.use_date) AS enddate
FROM (
SELECT
cte.use_date,
cte.rate_name,
cte.cages,
ROW_NUMBER() OVER (ORDER BY cte.rate_name, cte.use_date) - ROW_NUMBER() OVER (PARTITION BY cte.rate_name, cte.cages ORDER BY cte.use_date) AS grp
FROM cte
) a
GROUP BY a.rate_name, a.cages, a.grp
ORDER BY a.rate_name ASC, 3;
I ran this query within PL/SQL and it seems to work perfectly for what I'm trying to do. When I tried plugging in the solution in the software tool that we're using it turns out it doesn't support ROW_NUMBER(), OVER, and PARTITION BY.
Is there a way I could achieve the same results without having to use those built-in functionalities?
I've started looking at implementing the ROW_NUMBER() manually and found this approach. It seems to work when I tested it but I haven't really plugged it in. I'm now a bit stuck with implementing PARTITION BY and I just feel a little lost and don't know whether I'm heading in the right direction here.
EDIT
I just noticed that the query returns an incorrect result.
For I1 with 7 cages there should be 2 rows returned. The first row starts and ends on 2017-11-07 while the second row start on 2017-11-10 and ends on 2017-11-11.
Well, this is a little awkward, but it's the first thing I thought of. I'm sure it can be cleaned up. I had to make a second-level CTE to get it to work without any functions or anything. Probably would've been easier with connect by or lag, but I'm guessing your software tool can't handle those either.
WITH cte(rate_name, cages, use_date) AS (
SELECT 'I1', 8, DATE'2017-11-04' FROM DUAL UNION ALL
SELECT 'I1', 8, DATE'2017-11-05' FROM DUAL UNION ALL
SELECT 'I1', 7, DATE'2017-11-07' FROM DUAL UNION ALL
SELECT 'I1', 7, DATE'2017-11-10' FROM DUAL UNION ALL
SELECT 'I1', 7, DATE'2017-11-11' FROM DUAL UNION ALL
SELECT 'I1', 8, DATE'2017-11-12' FROM DUAL UNION ALL
SELECT 'I1', 8, DATE'2017-11-13' FROM DUAL UNION ALL
SELECT 'I1', 8, DATE'2017-11-14' FROM DUAL UNION ALL
SELECT 'I1 - BR', 5, DATE'2017-11-01' FROM DUAL UNION ALL
SELECT 'I1 - BR', 5, DATE'2017-11-02' FROM DUAL UNION ALL
SELECT 'I1 - BR', 5, DATE'2017-11-03' FROM DUAL UNION ALL
SELECT 'I1 - BR', 5, DATE'2017-11-04' FROM DUAL UNION ALL
SELECT 'I1 - BR', 5, DATE'2017-11-05' FROM DUAL UNION ALL
SELECT 'I1 - BR', 1, DATE'2017-11-06' FROM DUAL UNION ALL
SELECT 'I1 - BR', 1, DATE'2017-11-07' FROM DUAL UNION ALL
SELECT 'I1 - BR', 1, DATE'2017-11-08' FROM DUAL UNION ALL
SELECT 'I1 - BR', 5, DATE'2017-11-09' FROM DUAL UNION ALL
SELECT 'I1 - BR', 5, DATE'2017-11-10' FROM DUAL UNION ALL
SELECT 'I1 - BR', 5, DATE'2017-11-11' FROM DUAL
),
recur as (
SELECT
c1.use_date,
c1.rate_name,
c1.cages,
case when c3.rate_name is null then c1.use_date else null end as start_date,
case when c2.rate_name is null then c1.use_date else null end as end_date
FROM cte c1
-- next day
left join cte c2 on c2.rate_name = c1.rate_name and c2.use_date = c1.use_date +1 and c2.cages = c1.cages
-- prev day
left join cte c3 on c3.rate_name = c1.rate_name and c3.use_date = c1.use_date -1 and c3.cages = c1.cages
)
select rate_name, cages, start_date,
(select min(e.end_date) from recur e
where e.rate_name = s.rate_name
and e.end_date >= s.start_date) as end_date
from recur s
where start_date is not null
order by rate_name, start_date;
I've a big SQL statement that looks similar to the one below.
As soon as there are more than 128 entries combined with union all, then I get this error: Too many Contexts of Relation-Procedure-Views. Maximum allowed is 255
How can I reformulate the query to get rid of the error?
There is no way to add this data to the database (it's in a script that does sanity checking of the database; the script has read-access only as the database can be in read-only mode).
Of the columns below:
id and identifier have distinct values in each row
id is the numeric ID and it have gaps that are known in advance
identifier is an alphanumeric name (so unlike the below query, you cannot generate identifier from id)
usage has two string values which are valid for certain groups of id (so I could put them in a separate union all construct)
comment has about 20 distinct string values which are valid for certain groups of id (so I could put them in a separate union all construct as well)
A query that reproduces this:
-- 20161024 - Too many Contexts of Relation-Procedure-Views. Maximum allowed is 255
with parameters as
(
select 1001 as id
, '1001' as usage
, 'PP_1001' as identifier
, '1001' as comment
from rdb$database
union all select 1002,'1002','PP_1002','1002' from rdb$database
union all select 1003,'1003','PP_1003','1003' from rdb$database
union all select 1004,'1004','PP_1004','1004' from rdb$database
union all select 1005,'1005','PP_1005','1005' from rdb$database
union all select 1006,'1006','PP_1006','1006' from rdb$database
union all select 1007,'1007','PP_1007','1007' from rdb$database
union all select 1008,'1008','PP_1008','1008' from rdb$database
union all select 1009,'1009','PP_1009','1009' from rdb$database
union all select 1010,'1010','PP_1010','1010' from rdb$database
union all select 1011,'1011','PP_1011','1011' from rdb$database
union all select 1012,'1012','PP_1012','1012' from rdb$database
union all select 1013,'1013','PP_1013','1013' from rdb$database
union all select 1014,'1014','PP_1014','1014' from rdb$database
union all select 1015,'1015','PP_1015','1015' from rdb$database
union all select 1016,'1016','PP_1016','1016' from rdb$database
union all select 1017,'1017','PP_1017','1017' from rdb$database
union all select 1018,'1018','PP_1018','1018' from rdb$database
union all select 1019,'1019','PP_1019','1019' from rdb$database
union all select 1020,'1020','PP_1020','1020' from rdb$database
union all select 1021,'1021','PP_1021','1021' from rdb$database
union all select 1022,'1022','PP_1022','1022' from rdb$database
union all select 1023,'1023','PP_1023','1023' from rdb$database
union all select 1024,'1024','PP_1024','1024' from rdb$database
union all select 1025,'1025','PP_1025','1025' from rdb$database
union all select 1026,'1026','PP_1026','1026' from rdb$database
union all select 1027,'1027','PP_1027','1027' from rdb$database
union all select 1028,'1028','PP_1028','1028' from rdb$database
union all select 1029,'1029','PP_1029','1029' from rdb$database
union all select 1030,'1030','PP_1030','1030' from rdb$database
union all select 1031,'1031','PP_1031','1031' from rdb$database
union all select 1032,'1032','PP_1032','1032' from rdb$database
union all select 1033,'1033','PP_1033','1033' from rdb$database
union all select 1034,'1034','PP_1034','1034' from rdb$database
union all select 1035,'1035','PP_1035','1035' from rdb$database
union all select 1036,'1036','PP_1036','1036' from rdb$database
union all select 1037,'1037','PP_1037','1037' from rdb$database
union all select 1038,'1038','PP_1038','1038' from rdb$database
union all select 1039,'1039','PP_1039','1039' from rdb$database
union all select 1040,'1040','PP_1040','1040' from rdb$database
union all select 1041,'1041','PP_1041','1041' from rdb$database
union all select 1042,'1042','PP_1042','1042' from rdb$database
union all select 1043,'1043','PP_1043','1043' from rdb$database
union all select 1044,'1044','PP_1044','1044' from rdb$database
union all select 1045,'1045','PP_1045','1045' from rdb$database
union all select 1046,'1046','PP_1046','1046' from rdb$database
union all select 1047,'1047','PP_1047','1047' from rdb$database
union all select 1048,'1048','PP_1048','1048' from rdb$database
union all select 1049,'1049','PP_1049','1049' from rdb$database
union all select 1050,'1050','PP_1050','1050' from rdb$database
union all select 1051,'1051','PP_1051','1051' from rdb$database
union all select 1052,'1052','PP_1052','1052' from rdb$database
union all select 1053,'1053','PP_1053','1053' from rdb$database
union all select 1054,'1054','PP_1054','1054' from rdb$database
union all select 1055,'1055','PP_1055','1055' from rdb$database
union all select 1056,'1056','PP_1056','1056' from rdb$database
union all select 1057,'1057','PP_1057','1057' from rdb$database
union all select 1058,'1058','PP_1058','1058' from rdb$database
union all select 1059,'1059','PP_1059','1059' from rdb$database
union all select 1060,'1060','PP_1060','1060' from rdb$database
union all select 1061,'1061','PP_1061','1061' from rdb$database
union all select 1062,'1062','PP_1062','1062' from rdb$database
union all select 1063,'1063','PP_1063','1063' from rdb$database
union all select 1064,'1064','PP_1064','1064' from rdb$database
union all select 1065,'1065','PP_1065','1065' from rdb$database
union all select 1066,'1066','PP_1066','1066' from rdb$database
union all select 1067,'1067','PP_1067','1067' from rdb$database
union all select 1068,'1068','PP_1068','1068' from rdb$database
union all select 1069,'1069','PP_1069','1069' from rdb$database
union all select 1070,'1070','PP_1070','1070' from rdb$database
union all select 1071,'1071','PP_1071','1071' from rdb$database
union all select 1072,'1072','PP_1072','1072' from rdb$database
union all select 1073,'1073','PP_1073','1073' from rdb$database
union all select 1074,'1074','PP_1074','1074' from rdb$database
union all select 1075,'1075','PP_1075','1075' from rdb$database
union all select 1076,'1076','PP_1076','1076' from rdb$database
union all select 1077,'1077','PP_1077','1077' from rdb$database
union all select 1078,'1078','PP_1078','1078' from rdb$database
union all select 1079,'1079','PP_1079','1079' from rdb$database
union all select 1080,'1080','PP_1080','1080' from rdb$database
union all select 1081,'1081','PP_1081','1081' from rdb$database
union all select 1082,'1082','PP_1082','1082' from rdb$database
union all select 1083,'1083','PP_1083','1083' from rdb$database
union all select 1084,'1084','PP_1084','1084' from rdb$database
union all select 1085,'1085','PP_1085','1085' from rdb$database
union all select 1086,'1086','PP_1086','1086' from rdb$database
union all select 1087,'1087','PP_1087','1087' from rdb$database
union all select 1088,'1088','PP_1088','1088' from rdb$database
union all select 1089,'1089','PP_1089','1089' from rdb$database
union all select 1090,'1090','PP_1090','1090' from rdb$database
union all select 1091,'1091','PP_1091','1091' from rdb$database
union all select 1092,'1092','PP_1092','1092' from rdb$database
union all select 1093,'1093','PP_1093','1093' from rdb$database
union all select 1094,'1094','PP_1094','1094' from rdb$database
union all select 1095,'1095','PP_1095','1095' from rdb$database
union all select 1096,'1096','PP_1096','1096' from rdb$database
union all select 1097,'1097','PP_1097','1097' from rdb$database
union all select 1098,'1098','PP_1098','1098' from rdb$database
union all select 1099,'1099','PP_1099','1099' from rdb$database
union all select 1100,'1100','PP_1100','1100' from rdb$database
union all select 1101,'1101','PP_1101','1101' from rdb$database
union all select 1102,'1102','PP_1102','1102' from rdb$database
union all select 1103,'1103','PP_1103','1103' from rdb$database
union all select 1104,'1104','PP_1104','1104' from rdb$database
union all select 1105,'1105','PP_1105','1105' from rdb$database
union all select 1106,'1106','PP_1106','1106' from rdb$database
union all select 1107,'1107','PP_1107','1107' from rdb$database
union all select 1108,'1108','PP_1108','1108' from rdb$database
union all select 1109,'1109','PP_1109','1109' from rdb$database
union all select 1110,'1110','PP_1110','1110' from rdb$database
union all select 1111,'1111','PP_1111','1111' from rdb$database
union all select 1112,'1112','PP_1112','1112' from rdb$database
union all select 1113,'1113','PP_1113','1113' from rdb$database
union all select 1114,'1114','PP_1114','1114' from rdb$database
union all select 1115,'1115','PP_1115','1115' from rdb$database
union all select 1116,'1116','PP_1116','1116' from rdb$database
union all select 1117,'1117','PP_1117','1117' from rdb$database
union all select 1118,'1118','PP_1118','1118' from rdb$database
union all select 1119,'1119','PP_1119','1119' from rdb$database
union all select 1120,'1120','PP_1120','1120' from rdb$database
union all select 1121,'1121','PP_1121','1121' from rdb$database
union all select 1122,'1122','PP_1122','1122' from rdb$database
union all select 1123,'1123','PP_1123','1123' from rdb$database
union all select 1124,'1124','PP_1124','1124' from rdb$database
union all select 1125,'1125','PP_1125','1125' from rdb$database
union all select 1126,'1126','PP_1126','1126' from rdb$database
union all select 1127,'1127','PP_1127','1127' from rdb$database
union all select 1128,'1128','PP_1128','1128' from rdb$database
--union all select 1129,'1129','PP_1129','1129' from rdb$database
)
select parameters.id
, parameters.usage
, parameters.identifier
, parameters.comment
from parameters
where parameters.id <> -1
order by parameters.id
A construct like the one below should get me going.
The params is a table in the database that needs to be compared to the artificial parameters table that is sparsely filled.
Techniques used:
recursive query to generate a sequence of ID values in IDs
case constructs to fill the columns
In the actual query there will be a case with when and then for all validId values and smaller case constructs for the columns needing less values.
Query without error:
select parameters.id
, parameters.usage
, parameters.identifier
, parameters.comment
, params.ID param_id
, params.AVALUE
, params.DESCRIPTION
from
(
with recursive IDs as
(
select 0 as ID from rdb$database
union all
select 1 + ID from IDs where ID < 1000
)
select
ID
, case
when ((ID = 999) or (ID between 0 and 130))
then 1
else 0
end as validId
, case
when ID in
(
3,
12, 13, 14, 15, 16, 17, 18, 19,
20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
41, 42, 46, 47,
50, 51, 52, 54, 55, 56, 57, 58, 59,
60, 61, 62, 63, 64, 65, 66, 67, 68, 69,
70, 71, 72, 79,
80, 83, 84, 85, 86, 87, 88, 89,
90, 91, 92, 93, 94, 95, 96, 97, 98, 99,
100, 101, 102, 103, 104, 105, 106, 107, 108, 109,
110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
120, 121, 122, 123, 124, 125, 126, 127, 129,
999
)
then 'used'
else 'unused'
end as usage
, '' as identifier
, '' as comment
from
IDs
) parameters
full outer join params
on params.ID = parameters.id
where parameters.validId = 1
order by params.id, parameters.id