Today I want to share a couple of SQLs which helps me to leverage workspaced repository tables.
The first one is a simple flat query of workspace affected objects. Same data you see when clicking workspace in Siebel Tools.Filter by the object name/type to get an idea of who is modifying/modified the object.
select w.name WS_NAME, w.status_cd WS_STATUS, v.VERSION_NUM WS_VER, pw.name BASE_WS_NAME,
u.fst_name WS_AUTHOR, o.OBJ_TYPE , o.OBJ_NAME, o.operation_cd, o.last_upd
from siebel.S_REPOSITORY r -- repository
join siebel.S_WORKSPACE pw on r.ROW_ID = pw.REPOSITORY_ID -- baseline workspace
join siebel.S_WORKSPACE w on w.PAR_WS_ID = pw.ROW_ID -- child / dev workspace with changes
join siebel.S_WS_VERSION v on v.ws_id = w.row_id -- versions of the workspace
join siebel.S_CONTACT u on u.ROW_ID = w.CREATED_BY -- ws author
join siebel.S_RTC_MOD_OBJ o on o.WS_VER_ID = v.ROW_ID and r.ROW_ID = o.REPOSITORY_ID -- modified objects
where r.name = 'Siebel Repository'
and w.NAME = 'dev_vbabkin_d412_1' -- filter by dev branch name
--and pw.NAME = 'int_dev' -- or baseline/parent branch name
--and o.obj_type = 'Business Component' and o.obj_name = 'Account' -- or by affected object
order by o.last_upd desc;
Keep in mind that SQL only lists top-level objects (Applet, BusComp, Picklist etc) without any specific details.
The second query gives full information about object modifications in delivered workspaces including each attribute across all sub-objects.When you deliver a workspace Siebel logs the history of all modifications done to the objects in your workspace. Below SQL just puts all the logs tables together.
select v.VERSION_NUM WS_VER, dw.name WS_NAME, u.fst_name AUTHOR, m.last_upd, w.name BASE_WS_NAME,
c.TOP_PARENT_TYPE TOP_OBJ_TYPE, c.TOP_PARENT_NAME TOP_OBJ_NAME,
c.obj_type, c.object_name,
a.attribute, NVL(a.old_cust_value, a.old_std_value) OLD_VAL, a.new_std_value NEW_VAL,
c.OBJ_NAME, c.STATUS
from siebel.S_REPOSITORY r -- repository
join siebel.S_WORKSPACE w on r.ROW_ID = w.REPOSITORY_ID -- baseline workspace
join siebel.S_WS_VERSION v on w.ROW_ID = v.WS_ID and r.ROW_ID = v.REPOSITORY_ID -- versions of baseline workspace
join siebel.S_WS_MERGE_LOG m on m.RESULT_WS_VER_ID = v.ROW_ID -- workspace merge info
join siebel.S_WS_VERSION dv on dv.ROW_ID = m.FROM_WS_VER_ID -- versions of delivered workspace
join siebel.S_WORKSPACE dw on dw.ROW_ID = dv.WS_ID -- delivered workspace (child branches)
join siebel.S_CONTACT u on u.ROW_ID = dw.CREATED_BY -- ws author
left join siebel.S_WS_MG_LOGOBJ c on c.WS_MERGE_LOG_ID = m.row_id -- modified child objects3445rg
left join siebel.S_WS_MG_LOGATTR a on a.ws_merge_log_id = m.row_id and a.ws_mg_logobj_id = c.row_id -- modified attributes
where r.name = 'Siebel Repository'
and w.NAME = 'int_dev' --filter by parent/destination/baseline workspace name
--and dw.name like 'dev_vbabkin_d412_1' -- by delivered workspace name
and c.TOP_PARENT_TYPE = 'Business Component' and c.TOP_PARENT_NAME = 'Account' -- by top level object
--and c.obj_type='Business Component User Prop' and c.object_name like 'Named Method%' -- by child object (could be same as top if you are looking for attrib changes)
--and a.attribute = 'Inactive' and a.new_std_value = 'Y' -- by attribute
order by v.VERSION_NUM desc, c.TOP_PARENT_NAME, c.object_name;
Unlike the first SQL it doesn't give you info about in-progress workspaces.
Finally, as a bonus below is a SQL to check if there is a workspace delivery in progress. Run it before delivering your workspace to avoid annoying "Another workspace delivery/rebase is in-progress. Please try after sometime." error with a failed workspace to be resubmitted.
DECLARE
wsname varchar(30) := 'int_dev'; -- baseline/parent workspace where you delivering to
BEGIN
SELECT name into wsname FROM siebel.S_WORKSPACE w WHERE w.name = wsname FOR UPDATE NOWAIT;
ROLLBACK;
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE = -54 THEN
raise_application_error(-20001, 'Another delivery in progress');
ELSE
ROLLBACK;
END IF;
END;
To be continued...
This is one of my favourite repository SQL statements. It connects all layers of Siebel application into one flat structure:
Application | Screen/View |
Applet | Control/List column |
Business Component | Field |
Table | Column |
Here are just a few of the questions it can answer:
I'll share the most full version of the SQL, but feel free to tune it up to your purpose.
SELECT distinct
t.NAME "TABLE", col.NAME "COLUMN",
b.NAME "BUSCOMP", f.NAME "FIELD",
nvl(ci.CAPTION, li.DISPLAY_NAME) "CAPTION", nvl(c.NAME, lc.NAME) "CONTROL", a.NAME "APPLET",
s.NAME "SCREEN", v.NAME "VIEW", ap.NAME "APPLICATION"
FROM siebel.S_REPOSITORY r
-- workspace
join siebel.S_WORKSPACE ws on ws.REPOSITORY_ID = r.ROW_ID
-- application
join siebel.S_APPLICATION ap on ap.REPOSITORY_ID = r.ROW_ID and ws.ROW_ID = ap.WS_ID
join siebel.S_PAGE_TAB aps on aps.APPLICATION_ID = ap.WS_SRC_ID and aps.INACTIVE_FLG = 'N' and ws.ROW_ID = aps.WS_ID
-- screen
join siebel.S_SCREEN s on s.name = aps.SCREEN_NAME and s.REPOSITORY_ID = r.ROW_ID AND s.INACTIVE_FLG = 'N' and ws.ROW_ID = s.WS_ID
join siebel.S_SCREEN_VIEW sv on sv.screen_id = s.WS_SRC_ID and sv.INACTIVE_FLG = 'N' and ws.ROW_ID = sv.WS_ID
-- view
join siebel.S_VIEW v on v.REPOSITORY_ID = r.ROW_ID and sv.VIEW_NAME = v.name and ws.ROW_ID = v.WS_ID
join siebel.S_VIEW_WEB_TMPL vt on vt.VIEW_ID = v.WS_SRC_ID and vt.INACTIVE_FLG = 'N' and ws.ROW_ID = vt.WS_ID
join siebel.S_VIEW_WTMPL_IT vti on vti.VIEW_WEB_TMPL_ID = vt.WS_SRC_ID and vti.INACTIVE_FLG = 'N' and ws.ROW_ID = vti.WS_ID
-- applet (only form, list applets)
join siebel.S_APPLET a on a.REPOSITORY_ID = r.ROW_ID and a.name = vti.APPLET_NAME and ws.ROW_ID = a.WS_ID
join siebel.S_APPL_WEB_TMPL w on w.applet_id = a.WS_SRC_ID and w.TYPE = vti.APPLET_MODE_CD and w.INACTIVE_FLG ='N' and ws.ROW_ID = w.WS_ID
join siebel.S_APPL_WTMPL_IT wi on wi.APPL_WEB_TMPL_ID = w.WS_SRC_ID and wi.INACTIVE_FLG = 'N' and ws.ROW_ID = wi.WS_ID
-- control
left join siebel.S_CONTROL c on c.APPLET_ID = a.WS_SRC_ID and wi.CTRL_NAME = c.name and c.INACTIVE_FLG = 'N' and ws.ROW_ID = c.WS_ID
left join siebel.S_LIST l on l.APPLET_ID = a.WS_SRC_ID and ws.ROW_ID = l.WS_ID
left join siebel.S_LIST_COLUMN lc on lc.LIST_ID = l.WS_SRC_ID and wi.CTRL_NAME = lc.name and ws.ROW_ID = lc.WS_ID
-- control caption (only overrides!)
left join siebel.S_CONTROL_INTL ci on ci.CONTROL_ID = c.WS_SRC_ID and ws.ROW_ID = ci.WS_ID
left join siebel.S_LIST_COL_INTL li on li.LIST_COLUMN_ID = lc.WS_SRC_ID and ws.ROW_ID = li.WS_ID
-- buscomp
join SIEBEL.S_BUSCOMP b on b.name = a.BUSCOMP_NAME and b.REPOSITORY_ID = r.ROW_ID and ws.ROW_ID = b.WS_ID
-- fields exposed either through control or list column
join siebel.S_FIELD f on f.BUSCOMP_ID = b.WS_SRC_ID
and (lc.FIELD_NAME = f.name or c.FIELD_NAME = f.name) and ws.ROW_ID = f.WS_ID
-- join
left join siebel.S_JOIN j on j.name = f.JOIN_NAME and j.BUSCOMP_ID = f.BUSCOMP_ID and ws.ROW_ID = j.WS_ID
-- table
join siebel.S_TABLE t on t.REPOSITORY_ID = r.ROW_ID
and (t.name = b.TABLE_NAME and f.join_name is null -- base table
or t.name = j.DEST_TBL_NAME and j.row_id is not null -- explicit joins
or t.name = f.JOIN_NAME and j.row_id is null) -- implicit joins
-- column
join siebel.S_COLUMN col on col.TBL_ID = t.ROW_ID and f.COL_NAME = col.name and ws.ROW_ID = c.WS_ID
WHERE r.name = 'Siebel Repository'
and ws.name = 'MAIN'
and ap.name LIKE 'Siebel Financial Services'
ORDER BY 1, 2, 3;
Keep in mind that the SQL:
Here is also a version for old Siebel repositories (non-workspace): Snippet
SELECT distinct
t.NAME "TABLE", col.NAME "COLUMN",
b.NAME "BUSCOMP", f.NAME "FIELD",
nvl(ci.CAPTION, li.DISPLAY_NAME) "CAPTION", nvl(c.NAME, lc.NAME) "CONTROL", a.NAME "APPLET",
s.NAME "SCREEN", v.NAME "VIEW", ap.NAME "APPLICATION"
FROM siebel.S_REPOSITORY r
-- application
join siebel.S_APPLICATION ap on ap.REPOSITORY_ID = r.ROW_ID
join siebel.S_PAGE_TAB aps on aps.APPLICATION_ID = ap.ROW_ID and aps.INACTIVE_FLG = 'N'
-- screen
join siebel.S_SCREEN s on s.name = aps.SCREEN_NAME and s.REPOSITORY_ID = r.ROW_ID AND s.INACTIVE_FLG = 'N'
join siebel.S_SCREEN_VIEW sv on sv.screen_id = s.ROW_ID and sv.INACTIVE_FLG = 'N'
-- view
join siebel.S_VIEW v on v.REPOSITORY_ID = r.ROW_ID and sv.VIEW_NAME = v.name
join siebel.S_VIEW_WEB_TMPL vt on vt.VIEW_ID = v.ROW_ID and vt.INACTIVE_FLG = 'N'
join siebel.S_VIEW_WTMPL_IT vti on vti.VIEW_WEB_TMPL_ID = vt.ROW_ID and vti.INACTIVE_FLG = 'N'
-- applet (only form, list applets)
join siebel.S_APPLET a on a.REPOSITORY_ID = r.ROW_ID and a.name = vti.APPLET_NAME
join siebel.S_APPL_WEB_TMPL w on w.applet_id = a.ROW_ID and w.TYPE = vti.APPLET_MODE_CD and w.INACTIVE_FLG ='N'
join siebel.S_APPL_WTMPL_IT wi on wi.APPL_WEB_TMPL_ID = w.ROW_ID and wi.INACTIVE_FLG = 'N'
-- control
left join siebel.S_CONTROL c on c.APPLET_ID = a.ROW_ID and wi.CTRL_NAME = c.name and c.INACTIVE_FLG = 'N'
left join siebel.S_LIST l on l.APPLET_ID = a.ROW_ID
left join siebel.S_LIST_COLUMN lc on lc.LIST_ID = l.ROW_ID and wi.CTRL_NAME = lc.name
-- control caption (only overrides!)
left join siebel.S_CONTROL_INTL ci on ci.CONTROL_ID = c.ROW_ID
left join siebel.S_LIST_COL_INTL li on li.LIST_COLUMN_ID = lc.ROW_ID
-- buscomp
join SIEBEL.S_BUSCOMP b on b.name = a.BUSCOMP_NAME and b.REPOSITORY_ID = r.ROW_ID
-- fields exposed either through control or list column
join siebel.S_FIELD f on f.BUSCOMP_ID = b.ROW_ID
and (lc.FIELD_NAME = f.name or c.FIELD_NAME = f.name)
-- join
left join siebel.S_JOIN j on j.name = f.JOIN_NAME and j.BUSCOMP_ID = f.BUSCOMP_ID
-- table
join siebel.S_TABLE t on t.REPOSITORY_ID = r.ROW_ID
and (t.name = b.TABLE_NAME and f.join_name is null -- base table
or t.name = j.DEST_TBL_NAME and j.row_id is not null -- explicit joins
or t.name = f.JOIN_NAME and j.row_id is null) -- implicit joins
-- column
join siebel.S_COLUMN col on col.TBL_ID = t.ROW_ID and f.COL_NAME = col.name
WHERE r.name = 'Siebel Repository'
and ap.name LIKE 'Siebel Financial Services'
ORDER BY 1, 2, 3;
Starting a series of SQLs to check the consistency of Siebel repository object.
And the first SQL is to identify Integration Component fields referencing non-existing BusComp fields:
with io as ( -- IO/IC/Field
SELECT io.repository_id, io.name IO, ic.name IC, ic.ext_name BC, nvl(ifu.value, iff.ext_name) FIELD
FROM siebel.S_INT_OBJ io
join siebel.S_INT_COMP ic on io.row_id = ic.int_obj_id
and ic.inactive_flg = 'N'
join siebel.S_INT_FIELD iff on iff.int_comp_id = ic.row_id
and iff.inactive_flg = 'N'
and iff.field_type_cd = 'Data'
left join siebel.S_INTFLD_UPROP ifu on ifu.int_field_id = iff.row_id -- MVF
and ifu.inactive_flg = 'N'
and ifu.name in ('MVGFieldName', 'AssocFieldName')
where io.base_obj_type = 'Siebel Business Object'
and io.inactive_flg = 'N'),
bc as ( -- BC/Field
select bc.repository_id, bc.name BC, f.name FIELD
from siebel.S_BUSCOMP bc
join siebel.S_FIELD f on f.buscomp_id = bc.row_id
and f.inactive_flg = 'N')
select io.io, io.ic, io.field, io.bc
from io
join siebel.S_REPOSITORY r on r.row_id = io.repository_id
where r.name = 'Siebel Repository'
and io.field not in ('Id','Conflict Id','Created','Created By','Mod Id','Updated','Updated By', 'SSA Primary Field', 'IsPrimaryMVG') -- excluding system fields
and (bc, field) not in (select bc, field from bc where repository_id = r.row_id)
and io.io like 'AMS%'; -- to filter by your project preffix
Do you remember a pain when calculated expression splits across dozens calculated fields?
That SQL will help you to visualise complex dependencies of calculated fields:
SELECT level,
SYS_CONNECT_BY_PATH(t.NAME, '/') PATH,
t.*
FROM
(SELECT f.NAME, f.CALCVAL
FROM siebel.S_FIELD f
JOIN siebel.S_BUSCOMP b ON b.row_id = f.BUSCOMP_ID
WHERE b.name = 'Order Entry - Orders' -- bus comp name
) t
START WITH name = 'Payment Order Total' -- field name
CONNECT BY prior CALCVAL LIKE '%[' || NAME || ']%'
ORDER BY 2;
It will show you all subsequent fields for vanilla calculated field [Payment Order Total] (BusComp = Order Entry - Orders) in recursion:
Here is a full version of SQL with more details
with t as (
select f.NAME, f.CALCVAL,
DECODE(f.MULTI_VALUED, 'Y', f.MVLINK_NAME || '.' || f.DEST_FLD_NAME,
DECODE(f.CALCULATED, 'Y', f.CALCVAL,
DECODE(f.JOIN_NAME, null, b.TABLE_NAME || '.' || f.COL_NAME,
DECODE(j.DEST_TBL_NAME, null, f.JOIN_NAME || '.' || f.COL_NAME,
j.DEST_TBL_NAME || '.' || f.COL_NAME)))) VAL
from siebel.S_FIELD f
join siebel.S_BUSCOMP b on b.row_id = f.BUSCOMP_ID
left join siebel.S_JOIN j on j.NAME = f.JOIN_NAME AND j.BUSCOMP_ID = f.BUSCOMP_ID
where b.name = 'Order Entry - Orders')
select distinct level, SYS_CONNECT_BY_PATH(t.NAME, '/') PATH, t.NAME, t.VAL from t
start with name = 'Payment Order Total'
connect by prior CALCVAL LIKE '%[' || NAME || ']%'
order by 2;