我的选择查询如下:
SELECT
R.ID_REQUEST, R.ID_PROJET, J.NAME, L.DATE_ACTION,L.NAME_ACTION
, LEAD(L.DATE_ACTION) OVER (PARTITION BY R.ID_REQUEST ORDER BY L.DATE_ACTION)- L.DATE_ACTION AS TOTAL_DAYS
FROM (REQUEST R LEFT JOIN LOG_TABLE L ON R.ID_REQUEST = L.ID_REQUEST)
LEFT JOIN JOB_TABLE J ON R.ID_JOB = J.ID_JOB
WHERE D.ID_REQUEST = 10
结果是这样的:
ID_REQUEST ID_PROJET NAME DATE_ACTION NAME_ACTION TOTAL_DAYS
10 152 pr1 01/01/2005 arbitrary_name1 3
10 152 pr1 04/01/2005 arbitrary_name2 1
10 152 pr1 05/01/2005 arbitrary_name3 null
我想要的是将动作的名称作为列。我知道我可以使用DECODE
(因为10g中没有pivot
)。但如何使用与列名称相同的操作名称?操作列表因请求而异。 (表log_table包含每个请求的操作,操作数是可变的)。
我希望我的问题足够清楚!感谢。
答案 0 :(得分:1)
This solution比一个比我更聪明的人在10或11上运行良好的列数。它唯一没做的就是订购列。 和实施
SELECT *
FROM TABLE(DYNAMIC_PIVOT(
'SELECT emp_no,dept_no from emp group by emp_no'));
CREATE OR REPLACE TYPE PIVOTIMPL AS OBJECT
(
--from here https://technology.amis.nl/2006/05/24/dynamic-sql-pivoting-stealing-antons-thunder/
RET_TYPE ANYTYPE, -- The return type of the table function
STMT VARCHAR2(32767),
FMT VARCHAR2(32767),
CUR INTEGER,
STATIC FUNCTION ODCITABLEDESCRIBE(RTYPE OUT ANYTYPE,
P_STMT IN VARCHAR2,
P_FMT IN VARCHAR2 := 'upper(@p@)',
DUMMY IN NUMBER := 0) RETURN NUMBER,
STATIC FUNCTION ODCITABLEPREPARE(SCTX OUT PIVOTIMPL,
TI IN SYS.ODCITABFUNCINFO,
P_STMT IN VARCHAR2,
P_FMT IN VARCHAR2 := 'upper(@p@)',
DUMMY IN NUMBER := 0) RETURN NUMBER,
STATIC FUNCTION ODCITABLESTART(SCTX IN OUT PIVOTIMPL,
P_STMT IN VARCHAR2,
P_FMT IN VARCHAR2 := 'upper(@p@)',
DUMMY IN NUMBER := 0) RETURN NUMBER,
MEMBER FUNCTION ODCITABLEFETCH(SELF IN OUT PIVOTIMPL,
NROWS IN NUMBER,
OUTSET OUT ANYDATASET) RETURN NUMBER,
MEMBER FUNCTION ODCITABLECLOSE(SELF IN PIVOTIMPL) RETURN NUMBER
)
/
prompt
prompt Creating function DYNAMIC_PIVOT
prompt ===============================
prompt
CREATE OR REPLACE FUNCTION BROO1APP.DYNAMIC_PIVOT(P_STMT IN VARCHAR2,
P_FMT IN VARCHAR2 := 'upper(@p@)',
DUMMY IN NUMBER := 0)
RETURN ANYDATASET
PIPELINED USING PIVOTIMPL;
/
prompt
prompt Creating type body PIVOTIMPL
prompt ============================
prompt
CREATE OR REPLACE TYPE BODY BROO1APP.PIVOTIMPL AS
STATIC FUNCTION ODCITABLEDESCRIBE(RTYPE OUT ANYTYPE,
P_STMT IN VARCHAR2,
P_FMT IN VARCHAR2 := 'upper(@p@)',
DUMMY IN NUMBER) RETURN NUMBER IS
ATYP ANYTYPE;
CUR INTEGER;
NUMCOLS NUMBER;
DESC_TAB DBMS_SQL.DESC_TAB2;
RC SYS_REFCURSOR;
T_C2 VARCHAR2(32767);
T_FMT VARCHAR2(1000);
BEGIN
CUR := DBMS_SQL.OPEN_CURSOR;
DBMS_SQL.PARSE(CUR, P_STMT, DBMS_SQL.NATIVE);
DBMS_SQL.DESCRIBE_COLUMNS2(CUR, NUMCOLS, DESC_TAB);
DBMS_SQL.CLOSE_CURSOR(CUR);
--
ANYTYPE.BEGINCREATE(DBMS_TYPES.TYPECODE_OBJECT, ATYP);
FOR I IN 1 .. NUMCOLS - 2 LOOP
ATYP.ADDATTR(DESC_TAB(I).COL_NAME,
CASE DESC_TAB(I).COL_TYPE
WHEN 1 THEN
DBMS_TYPES.TYPECODE_VARCHAR2
WHEN 2 THEN
DBMS_TYPES.TYPECODE_NUMBER
WHEN 9 THEN
DBMS_TYPES.TYPECODE_VARCHAR2
WHEN 11 THEN
DBMS_TYPES.TYPECODE_VARCHAR2 -- show rowid as varchar2
WHEN 12 THEN
DBMS_TYPES.TYPECODE_DATE
WHEN 208 THEN
DBMS_TYPES.TYPECODE_VARCHAR2 -- show urowid as varchar2
WHEN 96 THEN
DBMS_TYPES.TYPECODE_CHAR
WHEN 180 THEN
DBMS_TYPES.TYPECODE_TIMESTAMP
WHEN 181 THEN
DBMS_TYPES.TYPECODE_TIMESTAMP_TZ
WHEN 231 THEN
DBMS_TYPES.TYPECODE_TIMESTAMP_LTZ
WHEN 182 THEN
DBMS_TYPES.TYPECODE_INTERVAL_YM
WHEN 183 THEN
DBMS_TYPES.TYPECODE_INTERVAL_DS
END,
DESC_TAB(I).COL_PRECISION,
DESC_TAB(I).COL_SCALE,
CASE DESC_TAB(I).COL_TYPE
WHEN 11 THEN
18 -- for rowid col_max_len = 16, and 18 characters are shown
ELSE
DESC_TAB(I).COL_MAX_LEN
END,
DESC_TAB(I).COL_CHARSETID,
DESC_TAB(I).COL_CHARSETFORM);
END LOOP;
IF INSTR(P_FMT, '@p@') > 0 THEN
T_FMT := P_FMT;
ELSE
T_FMT := '@p@';
END IF;
OPEN RC FOR REPLACE('select distinct ' || T_FMT || '
from( ' || P_STMT || ' )
order by ' || T_FMT,
'@p@',
DESC_TAB(NUMCOLS - 1).COL_NAME);
LOOP
FETCH RC
INTO T_C2;
EXIT WHEN RC%NOTFOUND;
ATYP.ADDATTR(T_C2,
CASE DESC_TAB(NUMCOLS).COL_TYPE WHEN 1 THEN
DBMS_TYPES.TYPECODE_VARCHAR2 WHEN 2 THEN
DBMS_TYPES.TYPECODE_NUMBER WHEN 9 THEN
DBMS_TYPES.TYPECODE_VARCHAR2 WHEN 11 THEN
DBMS_TYPES.TYPECODE_VARCHAR2 -- show rowid as varchar2
WHEN 12 THEN DBMS_TYPES.TYPECODE_DATE WHEN 208 THEN
DBMS_TYPES.TYPECODE_UROWID WHEN 96 THEN
DBMS_TYPES.TYPECODE_CHAR WHEN 180 THEN
DBMS_TYPES.TYPECODE_TIMESTAMP WHEN 181 THEN
DBMS_TYPES.TYPECODE_TIMESTAMP_TZ WHEN 231 THEN
DBMS_TYPES.TYPECODE_TIMESTAMP_LTZ WHEN 182 THEN
DBMS_TYPES.TYPECODE_INTERVAL_YM WHEN 183 THEN
DBMS_TYPES.TYPECODE_INTERVAL_DS END,
DESC_TAB(NUMCOLS).COL_PRECISION,
DESC_TAB(NUMCOLS).COL_SCALE,
CASE DESC_TAB(NUMCOLS).COL_TYPE WHEN 11 THEN 18 -- for rowid col_max_len = 16, and 18 characters are shown
ELSE DESC_TAB(NUMCOLS).COL_MAX_LEN END,
DESC_TAB(NUMCOLS).COL_CHARSETID,
DESC_TAB(NUMCOLS).COL_CHARSETFORM);
END LOOP;
CLOSE RC;
ATYP.ENDCREATE;
ANYTYPE.BEGINCREATE(DBMS_TYPES.TYPECODE_TABLE, RTYPE);
RTYPE.SETINFO(NULL,
NULL,
NULL,
NULL,
NULL,
ATYP,
DBMS_TYPES.TYPECODE_OBJECT,
0);
RTYPE.ENDCREATE();
RETURN ODCICONST.SUCCESS;
EXCEPTION
WHEN OTHERS THEN
RETURN ODCICONST.ERROR;
END;
--
STATIC FUNCTION ODCITABLEPREPARE(SCTX OUT PIVOTIMPL,
TI IN SYS.ODCITABFUNCINFO,
P_STMT IN VARCHAR2,
P_FMT IN VARCHAR2 := 'upper(@p@)',
DUMMY IN NUMBER) RETURN NUMBER IS
PREC PLS_INTEGER;
SCALE PLS_INTEGER;
LEN PLS_INTEGER;
CSID PLS_INTEGER;
CSFRM PLS_INTEGER;
ELEM_TYP ANYTYPE;
ANAME VARCHAR2(30);
TC PLS_INTEGER;
BEGIN
TC := TI.RETTYPE.GETATTRELEMINFO(1,
PREC,
SCALE,
LEN,
CSID,
CSFRM,
ELEM_TYP,
ANAME);
--
IF INSTR(P_FMT, '@p@') > 0 THEN
SCTX := PIVOTIMPL(ELEM_TYP, P_STMT, P_FMT, NULL);
ELSE
SCTX := PIVOTIMPL(ELEM_TYP, P_STMT, '@p@', NULL);
END IF;
RETURN ODCICONST.SUCCESS;
END;
--
STATIC FUNCTION ODCITABLESTART(SCTX IN OUT PIVOTIMPL,
P_STMT IN VARCHAR2,
P_FMT IN VARCHAR2 := 'upper(@p@)',
DUMMY IN NUMBER) RETURN NUMBER IS
CUR INTEGER;
NUMCOLS NUMBER;
DESC_TAB DBMS_SQL.DESC_TAB2;
T_STMT VARCHAR2(32767);
TYPE_CODE PLS_INTEGER;
PREC PLS_INTEGER;
SCALE PLS_INTEGER;
LEN PLS_INTEGER;
CSID PLS_INTEGER;
CSFRM PLS_INTEGER;
SCHEMA_NAME VARCHAR2(30);
TYPE_NAME VARCHAR2(30);
VERSION VARCHAR2(30);
ATTR_COUNT PLS_INTEGER;
ATTR_TYPE ANYTYPE;
ATTR_NAME VARCHAR2(100);
DUMMY2 INTEGER;
FIRST_COL VARCHAR2(30);
BEGIN
CUR := DBMS_SQL.OPEN_CURSOR;
DBMS_SQL.PARSE(CUR, P_STMT, DBMS_SQL.NATIVE);
DBMS_SQL.DESCRIBE_COLUMNS2(CUR, NUMCOLS, DESC_TAB);
DBMS_SQL.CLOSE_CURSOR(CUR);
--
FOR I IN 1 .. NUMCOLS - 2 LOOP
T_STMT := T_STMT || ', "' || DESC_TAB(I).COL_NAME || '"';
END LOOP;
--
TYPE_CODE := SCTX.RET_TYPE.GETINFO(PREC,
SCALE,
LEN,
CSID,
CSFRM,
SCHEMA_NAME,
TYPE_NAME,
VERSION,
ATTR_COUNT);
FOR I IN NUMCOLS - 1 .. ATTR_COUNT LOOP
TYPE_CODE := SCTX.RET_TYPE.GETATTRELEMINFO(I,
PREC,
SCALE,
LEN,
CSID,
CSFRM,
ATTR_TYPE,
ATTR_NAME);
T_STMT := T_STMT ||
REPLACE(', max( decode( ' || SCTX.FMT || ', ''' ||
ATTR_NAME || ''', ' || DESC_TAB(NUMCOLS)
.COL_NAME || ' ) )',
'@p@',
DESC_TAB(NUMCOLS - 1).COL_NAME);
END LOOP;
T_STMT := 'select ' || SUBSTR(T_STMT, 2) || ' from ( ' || SCTX.STMT || ' )';
FOR I IN 1 .. NUMCOLS - 2 LOOP
IF I = 1 THEN
T_STMT := T_STMT || ' group by "' || DESC_TAB(I).COL_NAME || '"';
FIRST_COL := DESC_TAB(I).COL_NAME;
ELSE
T_STMT := T_STMT || ', "' || DESC_TAB(I).COL_NAME || '"';
END IF;
END LOOP;
T_STMT := T_STMT || ' ORDER BY "' || FIRST_COL || '"';
--
DBMS_OUTPUT.PUT_LINE(T_STMT);
SCTX.CUR := DBMS_SQL.OPEN_CURSOR;
DBMS_SQL.PARSE(SCTX.CUR, T_STMT, DBMS_SQL.NATIVE);
FOR I IN 1 .. ATTR_COUNT LOOP
TYPE_CODE := SCTX.RET_TYPE.GETATTRELEMINFO(I,
PREC,
SCALE,
LEN,
CSID,
CSFRM,
ATTR_TYPE,
ATTR_NAME);
CASE TYPE_CODE
WHEN DBMS_TYPES.TYPECODE_CHAR THEN
DBMS_SQL.DEFINE_COLUMN(SCTX.CUR, I, 'x', 32767);
WHEN DBMS_TYPES.TYPECODE_VARCHAR2 THEN
DBMS_SQL.DEFINE_COLUMN(SCTX.CUR, I, 'x', 32767);
WHEN DBMS_TYPES.TYPECODE_NUMBER THEN
DBMS_SQL.DEFINE_COLUMN(SCTX.CUR, I, CAST(NULL AS NUMBER));
WHEN DBMS_TYPES.TYPECODE_DATE THEN
DBMS_SQL.DEFINE_COLUMN(SCTX.CUR, I, CAST(NULL AS DATE));
WHEN DBMS_TYPES.TYPECODE_UROWID THEN
DBMS_SQL.DEFINE_COLUMN(SCTX.CUR, I, CAST(NULL AS UROWID));
WHEN DBMS_TYPES.TYPECODE_TIMESTAMP THEN
DBMS_SQL.DEFINE_COLUMN(SCTX.CUR, I, CAST(NULL AS TIMESTAMP));
WHEN DBMS_TYPES.TYPECODE_TIMESTAMP_TZ THEN
DBMS_SQL.DEFINE_COLUMN(SCTX.CUR, I, CAST(NULL AS TIMESTAMP WITH TIME ZONE));
WHEN DBMS_TYPES.TYPECODE_TIMESTAMP_LTZ THEN
DBMS_SQL.DEFINE_COLUMN(SCTX.CUR, I, CAST(NULL AS TIMESTAMP WITH LOCAL TIME ZONE));
WHEN DBMS_TYPES.TYPECODE_INTERVAL_YM THEN
DBMS_SQL.DEFINE_COLUMN(SCTX.CUR,
I,
CAST(NULL AS INTERVAL YEAR TO MONTH));
WHEN DBMS_TYPES.TYPECODE_INTERVAL_DS THEN
DBMS_SQL.DEFINE_COLUMN(SCTX.CUR,
I,
CAST(NULL AS INTERVAL DAY TO SECOND));
END CASE;
END LOOP;
DUMMY2 := DBMS_SQL.EXECUTE(SCTX.CUR);
RETURN ODCICONST.SUCCESS;
END;
--
MEMBER FUNCTION ODCITABLEFETCH(SELF IN OUT PIVOTIMPL,
NROWS IN NUMBER,
OUTSET OUT ANYDATASET) RETURN NUMBER IS
C1_COL_TYPE PLS_INTEGER;
TYPE_CODE PLS_INTEGER;
PREC PLS_INTEGER;
SCALE PLS_INTEGER;
LEN PLS_INTEGER;
CSID PLS_INTEGER;
CSFRM PLS_INTEGER;
SCHEMA_NAME VARCHAR2(30);
TYPE_NAME VARCHAR2(30);
VERSION VARCHAR2(30);
ATTR_COUNT PLS_INTEGER;
ATTR_TYPE ANYTYPE;
ATTR_NAME VARCHAR2(100);
V1 VARCHAR2(32767);
N1 NUMBER;
D1 DATE;
UR1 UROWID;
IDS1 INTERVAL DAY TO SECOND;
IYM1 INTERVAL YEAR TO MONTH;
TS1 TIMESTAMP;
TSTZ1 TIMESTAMP WITH TIME ZONE;
TSLTZ1 TIMESTAMP WITH LOCAL TIME ZONE;
BEGIN
OUTSET := NULL;
IF NROWS < 1 THEN
-- is this possible???
RETURN ODCICONST.SUCCESS;
END IF;
--
DBMS_OUTPUT.PUT_LINE('fetch');
IF DBMS_SQL.FETCH_ROWS(SELF.CUR) = 0 THEN
RETURN ODCICONST.SUCCESS;
END IF;
--
DBMS_OUTPUT.PUT_LINE('done');
TYPE_CODE := SELF.RET_TYPE.GETINFO(PREC,
SCALE,
LEN,
CSID,
CSFRM,
SCHEMA_NAME,
TYPE_NAME,
VERSION,
ATTR_COUNT);
ANYDATASET.BEGINCREATE(DBMS_TYPES.TYPECODE_OBJECT,
SELF.RET_TYPE,
OUTSET);
OUTSET.ADDINSTANCE;
OUTSET.PIECEWISE();
FOR I IN 1 .. ATTR_COUNT LOOP
TYPE_CODE := SELF.RET_TYPE.GETATTRELEMINFO(I,
PREC,
SCALE,
LEN,
CSID,
CSFRM,
ATTR_TYPE,
ATTR_NAME);
DBMS_OUTPUT.PUT_LINE(ATTR_NAME);
CASE TYPE_CODE
WHEN DBMS_TYPES.TYPECODE_CHAR THEN
DBMS_SQL.COLUMN_VALUE(SELF.CUR, I, V1);
OUTSET.SETCHAR(V1);
WHEN DBMS_TYPES.TYPECODE_VARCHAR2 THEN
DBMS_SQL.COLUMN_VALUE(SELF.CUR, I, V1);
OUTSET.SETVARCHAR2(V1);
WHEN DBMS_TYPES.TYPECODE_NUMBER THEN
DBMS_SQL.COLUMN_VALUE(SELF.CUR, I, N1);
OUTSET.SETNUMBER(N1);
WHEN DBMS_TYPES.TYPECODE_DATE THEN
DBMS_SQL.COLUMN_VALUE(SELF.CUR, I, D1);
OUTSET.SETDATE(D1);
WHEN DBMS_TYPES.TYPECODE_UROWID THEN
DBMS_SQL.COLUMN_VALUE(SELF.CUR, I, UR1);
OUTSET.SETUROWID(UR1);
WHEN DBMS_TYPES.TYPECODE_INTERVAL_DS THEN
DBMS_SQL.COLUMN_VALUE(SELF.CUR, I, IDS1);
OUTSET.SETINTERVALDS(IDS1);
WHEN DBMS_TYPES.TYPECODE_INTERVAL_YM THEN
DBMS_SQL.COLUMN_VALUE(SELF.CUR, I, IYM1);
OUTSET.SETINTERVALYM(IYM1);
WHEN DBMS_TYPES.TYPECODE_TIMESTAMP THEN
DBMS_SQL.COLUMN_VALUE(SELF.CUR, I, TS1);
OUTSET.SETTIMESTAMP(TS1);
WHEN DBMS_TYPES.TYPECODE_TIMESTAMP_TZ THEN
DBMS_SQL.COLUMN_VALUE(SELF.CUR, I, TSTZ1);
OUTSET.SETTIMESTAMPTZ(TSTZ1);
WHEN DBMS_TYPES.TYPECODE_TIMESTAMP_LTZ THEN
DBMS_SQL.COLUMN_VALUE(SELF.CUR, I, TSLTZ1);
OUTSET.SETTIMESTAMPLTZ(TSLTZ1);
END CASE;
END LOOP;
OUTSET.ENDCREATE;
RETURN ODCICONST.SUCCESS;
END;
--
MEMBER FUNCTION ODCITABLECLOSE(SELF IN PIVOTIMPL) RETURN NUMBER IS
C INTEGER;
BEGIN
C := SELF.CUR;
DBMS_SQL.CLOSE_CURSOR(C);
RETURN ODCICONST.SUCCESS;
END;
END;
/