使用动态sql为select语句创建列

时间:2018-02-12 11:19:29

标签: sql oracle plsql dynamic-sql

我正在为分页结果编写存储过程,这个结果可以按某些值排序。我在select语句中确实有一个switch case,但因为它试图在rownum上执行orderby,所以它非常慢。

现在我正在尝试使用dyanmic sql在select之外构建查询,但我不知道我在做什么是可能的。

这是Oracle SQL Developer中的SQL:

create or replace PROCEDURE Sp_tsa_trainees_pagination (
schemeid IN INT,
searchval IN VARCHAR2,
pagesize IN INT DEFAULT 20,
currentpage IN INT DEFAULT 1,
--orderby IN VARCHAR2,
cursor_  OUT SYS_REFCURSOR)

AS
-- LOCAL VARIABLES
totalcount INT;
numberofpages INT;
startposition NUMBER;
endposition NUMBER;
orderby VARCHAR2(100) := 'surname asc' ;
dynamic_query VARCHAR(255) := 'row_number() over (order by t.SURNAME DESC, t.FORENAMES DESC) AS rnum';
BEGIN

-- Get total number of trainees in scheme
select COUNT(t.ORG_REGISTRATION_ID) 
into totalcount FROM v_trainee t 
where t.ORG_REGISTRATION_ID = schemeid 
AND t.status = 'A' and LOWER(t.trainee_name) like '%' || LOWER(searchval) || '%';

  -- calculate number of pages in the pagination by dividing total number of records by how many to display for each page
  numberofpages := totalcount / pagesize;

  -- get start position by multiplying number of records to display for each page by current page
  startposition := pagesize *( currentpage-1);

  -- add calculated start position by number of records to display to get end position
  endposition := startposition + pagesize;

  CASE orderby 
    WHEN 'surname desc' THEN dynamic_query := 'row_number() over (order by t.SURNAME DESC, t.FORENAMES DESC) AS rnum';
    WHEN 'surname asc' THEN dynamic_query := 'row_number() over (order by t.SURNAME ASC, t.FORENAMES ASC) AS rnum';
END CASE;


    OPEN cursor_ FOR
    Select * from 
(
SELECT 
-- order by based on selection

dynamic_query rnum,

t.ORG_REGISTRATION_ID SearchId,
    t.FORENAMES Forenames,
    t.FORENAME Forename,
    t.SURNAME Surname,
    t.person_id PersonId,
    t.trainee_name TraineeName,
    t.STATUS Status,
    t.IPD_ANNUAL_REVIEW_DATE AnnualReviewDate,
    t.ANNUAL_REVIEW_STATUS AnnualReviewStatus,
    t.payment_received PaymentRecieved,
    t.TRAINEE_ID TraineeId,
    t.IPD_SIGNUP_DATE IpdSignupDate,
    t.START_DATE StartDate,
    t.END_DATE EndDate,
    t.LENGTH_ON_SCHEME LengthOnScheme,
    t.EMPLOYEE_NUMBER EmploymentNumber,
    t.SELECTED_LEVEL SelectedLevel,
    t.SELECTED_LEVEL_DESCRIPTION SelectedLevelDescription,
    t.ELIGIBLE_LEVEL EligibleLevel,
    t.ELIGIBLE_LEVEL_DESCRIPTION EligibleLevelDescription,
    sce.FORENAMES SceForenames,
    sce.FORENAME SceForename,
    sce.SURNAME SceSurname,
    sce.mentor_name SceName,
    sce.EMPLOYEE_NUMBER SceEmployeeNumber,
    de.FORENAMES DeForenames,
    de.FORENAME DeForename,
    de.SURNAME DeSurname,
    de.mentor_name DeName,
    de.EMPLOYEE_NUMBER DeEmployeeNumber,
    t.COMPLETED_ATTRIBUTE_LEVELS CompletedAttributeLevels,
    t.ATTRIBUTE_LEVEL_COUNT AttributeLevelCount,

    -- get percentage
    CASE t.ATTRIBUTE_LEVEL_COUNT
    WHEN 0 THEN 0
    ELSE
    COMPLETED_ATTRIBUTE_LEVELS / t.ATTRIBUTE_LEVEL_COUNT * 100
    END percentage,

    DECODE(F_ISTRAINEEGROUPMEMBER(t.ORG_REGISTRATION_ID, 'S', t.person_id),'Y','N','Y') WithoutTsaGroup,
    orr.status SchemeStatus,
    (select count(*) from TRAINING_GROUP_TRAINEE tgt where tgt.trainee_id = t.TRAINEE_ID) NUMBER_OF_GROUPS,
    TotalCount
  FROM v_trainee t
  INNER JOIN org_registration orr ON t.ORG_REGISTRATION_ID = orr.id
  LEFT OUTER JOIN v_mentor sce    ON t.sce_id = sce.MENTOR_ID
  LEFT OUTER JOIN v_mentor de     ON t.de_id = de.MENTOR_ID
  where t.ORG_REGISTRATION_ID = schemeid  AND t.status = 'A' 
  and LOWER(t.trainee_name) like '%' || LOWER(searchval) || '%'
  )
  where rnum >= startposition and rnum <= endposition;

END;

我想将此变量与指定的sql一起使用:

dynamic_query rnum,

但是当我执行存储过程时,我收到了这个错误:

  

ORA-01722:无效的数字ORA-06512:at   “db.SP_TSA_TRAINEES_PAGINATION”,第46行ORA-06512:第13行

所以基本上我的问题是我可以将一个SQL分配给VARCHAR2然后动态地在select语句中使用它。

1 个答案:

答案 0 :(得分:0)

您可能需要动态SQL。例如:

create or replace procedure testDyn(n in number, C OUT SYS_REFCURSOR) is
    vDynamicPart varchar2(1000);
    vSQl         varchar2(1000);
begin
    --
    if  (n = 1) then
        vDynamicPart := 'count(1)';
    else
        vDynamicPart := 'count(null)';
    end if;
    --
    vSQl := 'select ' || vDynamicPart || ' from dual';
    open C for vSQl;
end;

如果你打电话

declare
    n1 number;
    n2 number;
    C1 SYS_REFCURSOR;
    C2 SYS_REFCURSOR;
begin
    testDyn(1, C1);
    testDyn(2, C2);

    fetch C1 into n1;
    fetch C2 into n2;

    dbms_output.put_line('n1: ' || n1);
    dbms_output.put_line('n2: ' || n2);
end;

你得到:

n1: 1
n2: 0