Last active
April 12, 2023 21:16
-
-
Save forstie/c43480aee468b2a0d8ff486d3018a948 to your computer and use it in GitHub Desktop.
The request... change Db2 for i to allow ORDER BY on CREATE VIEW. Well, we aren't going to do that because its non-standard. This gist shows a path forward using the existing support.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- | |
-- Subject: Bringing ORDER to a VIEW | |
-- Author: Scott Forstie | |
-- Date : February, 2023 | |
-- Features Used : This Gist uses UDTFs, SQL DDL, PIPE, SQL PL, SQL global variables | |
-- | |
-- Notes: | |
-- =============================================== | |
-- The SQL Standard dictates that the ORDER BY clause cannot be | |
-- includes in the CREATE VIEW defintion. | |
-- | |
-- Please keep in mind that by the letter of the query engine law, if you do NOT | |
-- include an ORDER BY, you are NOT guaranteed that rows will be returned in a | |
-- specific order. Period. That said, I have found this technique to be reliable-ish. | |
-- | |
-- This gist shows how to circumnavigate! | |
stop; | |
-- | |
-- Review the largest tables in System Limits | |
-- | |
WITH X AS (SELECT ROW_NUMBER() | |
OVER(PARTITION BY SYSTEM_SCHEMA_NAME, | |
SYSTEM_OBJECT_NAME, SYSTEM_TABLE_MEMBER ORDER BY | |
CURRENT_VALUE DESC NULLS LAST) AS R, U.* | |
FROM QSYS2.SYSLIMITS U | |
WHERE LIMIT_ID = 15000) | |
SELECT LAST_CHANGE_TIMESTAMP, SYSTEM_SCHEMA_NAME, | |
SYSTEM_OBJECT_NAME, SYSTEM_TABLE_MEMBER, | |
CURRENT_VALUE | |
FROM X WHERE R = 1 | |
ORDER BY CURRENT_VALUE DESC; | |
stop; | |
-- | |
-- Boy, I love that query, but it seems like a better fit for a view! | |
-- | |
create or replace view coolstuff.thebiggies as | |
WITH X AS (SELECT ROW_NUMBER() | |
OVER(PARTITION BY SYSTEM_SCHEMA_NAME, | |
SYSTEM_OBJECT_NAME, SYSTEM_TABLE_MEMBER ORDER BY | |
CURRENT_VALUE DESC NULLS LAST) AS R, U.* | |
FROM QSYS2.SYSLIMITS U | |
WHERE LIMIT_ID = 15000) | |
SELECT LAST_CHANGE_TIMESTAMP, SYSTEM_SCHEMA_NAME, | |
SYSTEM_OBJECT_NAME, SYSTEM_TABLE_MEMBER, | |
CURRENT_VALUE | |
FROM X WHERE R = 1; | |
-- ORDER BY CURRENT_VALUE DESC; <<=== the order by is not permitted! | |
stop; | |
-- | |
-- Ew, I lost my ordering! | |
-- | |
select * | |
from coolstuff.thebiggies; | |
stop; | |
-- | |
-- Consolidate the query logic into a UDTF | |
-- | |
create or replace function coolstuff.thebiggies () | |
returns table ( | |
last_chg timestamp, lib_name varchar(10) for sbcs data, file_name varchar(10) for sbcs data, | |
mbr_name varchar(10) for sbcs data, file_size bigint | |
) | |
not deterministic | |
external action | |
modifies sql data | |
not fenced | |
set option COMMIT = *NONE | |
begin | |
declare local_sqlcode integer; | |
declare local_sqlstate char(5); | |
declare not_found condition for '02000'; | |
declare at_end integer default 0; | |
declare rows_returned integer default 0; | |
declare v_error integer default 0; | |
declare v_message_text varchar(70); | |
declare v_last_chg timestamp; | |
declare v_lib_name varchar(10) for sbcs data; | |
declare v_pgm_name varchar(10) for sbcs data; | |
declare v_mbr_name varchar(10) for sbcs data; | |
declare v_file_size bigint; | |
declare find_biggies_text varchar(1000) for sbcs data default ' WITH X AS (SELECT ROW_NUMBER() | |
OVER(PARTITION BY SYSTEM_SCHEMA_NAME, | |
SYSTEM_OBJECT_NAME, SYSTEM_TABLE_MEMBER ORDER BY | |
CURRENT_VALUE DESC NULLS LAST) AS R, U.* | |
FROM QSYS2.SYSLIMITS U | |
WHERE LIMIT_ID = 15000) | |
SELECT LAST_CHANGE_TIMESTAMP, SYSTEM_SCHEMA_NAME, | |
SYSTEM_OBJECT_NAME, SYSTEM_TABLE_MEMBER, | |
CURRENT_VALUE | |
FROM X WHERE R = 1 | |
ORDER BY CURRENT_VALUE DESC'; | |
declare c_find_biggies cursor for find_biggies_stmt; | |
declare continue handler for not_found set at_end = 1; | |
declare continue handler for SQLEXCEPTION | |
begin | |
get diagnostics condition 1 | |
local_sqlcode = db2_returned_sqlcode, local_sqlstate = returned_sqlstate; | |
set v_message_text = 'coolstuff.thebiggies() failed with: ' concat local_sqlcode concat | |
' AND ' concat local_sqlstate; | |
signal sqlstate 'QPC01' | |
set message_text = v_message_text; | |
end; | |
prepare find_biggies_stmt from find_biggies_text; | |
open c_find_biggies; | |
set at_end = 0; | |
fetch from c_find_biggies | |
into v_last_chg, v_lib_name, v_pgm_name, v_mbr_name, v_file_size; | |
while (at_end = 0) do | |
pipe (v_last_chg, v_lib_name, v_pgm_name, v_mbr_name, v_file_size); | |
set rows_returned = rows_returned + 1; | |
set at_end = 0; | |
fetch from c_find_biggies | |
into v_last_chg, v_lib_name, v_pgm_name, v_mbr_name, v_file_size; | |
end while; | |
close c_find_biggies; | |
return; | |
end; | |
stop; | |
-- | |
-- Boy, I love that query, but it seems like a better fit for a view! | |
-- | |
create or replace view coolstuff.thebiggies as | |
select * | |
from table ( | |
coolstuff.thebiggies() | |
); | |
stop; | |
-- Test the View | |
-- | |
SELECT * | |
FROM coolstuff.thebiggies ; | |
stop; | |
-- | |
-- Bonus topic | |
-- | |
create or replace variable coolstuff.limit integer default 10; | |
stop; | |
-- | |
-- Do it again | |
-- | |
create or replace function coolstuff.thebiggies () | |
returns table ( | |
last_chg timestamp, lib_name varchar(10) for sbcs data, file_name varchar(10) for sbcs data, | |
mbr_name varchar(10) for sbcs data, file_size bigint | |
) | |
not deterministic | |
external action | |
modifies sql data | |
not fenced | |
set option COMMIT = *NONE | |
begin | |
declare local_sqlcode integer; | |
declare local_sqlstate char(5); | |
declare not_found condition for '02000'; | |
declare at_end integer default 0; | |
declare rows_returned integer default 0; | |
declare v_error integer default 0; | |
declare v_message_text varchar(70); | |
declare v_last_chg timestamp; | |
declare v_lib_name varchar(10) for sbcs data; | |
declare v_pgm_name varchar(10) for sbcs data; | |
declare v_mbr_name varchar(10) for sbcs data; | |
declare v_file_size bigint; | |
declare find_biggies_text varchar(1000) for sbcs data default ' WITH X AS (SELECT ROW_NUMBER() | |
OVER(PARTITION BY SYSTEM_SCHEMA_NAME, | |
SYSTEM_OBJECT_NAME, SYSTEM_TABLE_MEMBER ORDER BY | |
CURRENT_VALUE DESC NULLS LAST) AS R, U.* | |
FROM QSYS2.SYSLIMITS U | |
WHERE LIMIT_ID = 15000) | |
SELECT LAST_CHANGE_TIMESTAMP, SYSTEM_SCHEMA_NAME, | |
SYSTEM_OBJECT_NAME, SYSTEM_TABLE_MEMBER, | |
CURRENT_VALUE | |
FROM X WHERE R = 1 | |
ORDER BY CURRENT_VALUE DESC'; | |
declare c_find_biggies cursor for find_biggies_stmt; | |
declare continue handler for not_found set at_end = 1; | |
declare continue handler for SQLEXCEPTION | |
begin | |
get diagnostics condition 1 | |
local_sqlcode = db2_returned_sqlcode, local_sqlstate = returned_sqlstate; | |
set v_message_text = 'coolstuff.thebiggies() failed with: ' concat local_sqlcode concat | |
' AND ' concat local_sqlstate; | |
signal sqlstate 'QPC01' | |
set message_text = v_message_text; | |
end; | |
prepare find_biggies_stmt from find_biggies_text; | |
open c_find_biggies; | |
set at_end = 0; | |
fetch from c_find_biggies | |
into v_last_chg, v_lib_name, v_pgm_name, v_mbr_name, v_file_size; | |
while (at_end = 0 and rows_returned < coolstuff.limit) do | |
pipe (v_last_chg, v_lib_name, v_pgm_name, v_mbr_name, v_file_size); | |
set rows_returned = rows_returned + 1; | |
set at_end = 0; | |
fetch from c_find_biggies | |
into v_last_chg, v_lib_name, v_pgm_name, v_mbr_name, v_file_size; | |
end while; | |
close c_find_biggies; | |
return; | |
end; | |
stop; | |
-- | |
-- Test the View, with a built-in LIMIT control | |
-- (returns top 10 by default) | |
-- | |
SELECT * | |
FROM coolstuff.thebiggies ; | |
stop; | |
-- | |
-- Test the View, with a built-in LIMIT control | |
-- (return top 20) | |
-- | |
set coolstuff.limit = 20; | |
SELECT * | |
FROM coolstuff.thebiggies ; | |
stop; | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment