How Can I Make Oracle Query Sort Order Dynamic?

最后都变了- 提交于 2019-12-02 09:21:58

问题


I have a Oracle procedure inside a package like this

PROCEDURE getEmployee
(
  pinLanguage               IN    VARCHAR2,
  pinPage                   IN    NUMBER,
  pinPageSize               IN    NUMBER,
  pinSortColumn             IN    VARCHAR2,
  pinSortOrder              IN    VARCHAR2,
  poutEmployeeCursor        OUT   SYS_REFCURSOR
)
AS
BEGIN
    OPEN poutEmployeeCursor FOR
    SELECT * FROM (
      SELECT EMPLOYEE_ID, USERNAME, FULL_NAME, DATE_OF_BIRTH, EMP.GENDER_ID, GEN_TR.GENDER, EMP.WORK_TYPE_ID, WT_TR.WORK_TYPE, SALARY, EMAIL, PROFILE_IMAGE,
      ROW_NUMBER() OVER (ORDER BY EMPLOYEE_ID ASC) RN

      FROM EMPLOYEES EMP
      INNER JOIN GENDERS GEN ON EMP.GENDER_ID = GEN.GENDER_ID
      LEFT JOIN GENDERS_MLD GEN_TR ON GEN.GENDER_ID = GEN_TR.GENDER_ID AND GEN_TR.LANGUAGE = pinLanguage
      INNER JOIN WORK_TYPES WT ON EMP.WORK_TYPE_ID = WT.WORK_TYPE_ID
      LEFT JOIN WORK_TYPES_MLD WT_TR ON WT.WORK_TYPE_ID = WT_TR.WORK_TYPE_ID AND WT_TR.LANGUAGE = pinLanguage
    )
    WHERE RN BETWEEN (((pinPage - 1) * pinPageSize) + 1) AND (pinPage * pinPageSize);
END;

I need to make the sort order of the above query dynamic

If I pass the text FullName to pinSortColumn parameter, it need to sort FULL_NAME column

If I pass the text DateOfBirth to pinSortColumn parameter, it need to sort DATE_OF_BIRTH column

If I pass the text Gender to pinSortColumn parameter, it need to sort GEN_TR.GENDER column

I can pass the text asc or desc to pinSortOrder parameter and the query need to be sorted accordingly. Can you please help me to achieve this?


回答1:


You can use separate order by for asc and desc as following:

ORDER BY 
CASE pinSortOrder WHEN 'asc' THEN
    CASE pinSortColumn 
      WHEN 'FullName' THEN FULL_NAME 
      WHEN 'DateOfBirth' THEN to_char(DATE_OF_BIRTH,'yyyymmddhh24miss')
      WHEN 'Gender' THEN GEN_TR.GENDER   
    END
END,
CASE pinSortOrder WHEN 'desc' THEN
    CASE pinSortColumn 
      WHEN 'FullName' THEN FULL_NAME 
      WHEN 'DateOfBirth' THEN to_char(DATE_OF_BIRTH,'yyyymmddhh24miss')
      WHEN 'Gender' THEN GEN_TR.GENDER   
    END
END DESC

Let's say you have passed pinSortColumn as FullName and pinSortOrder as asc then order by clause will be ORDER BY FULL_NAME, NULL DESC (please note that default order will be asc so I have not write it in the code. Query will be ordered by FULL_NAME in ascending manner)

Now, If you have passed pinSortColumn as FullName and pinSortOrder as desc then order by clause will be ORDER BY NULL, FULL_NAME DESC.

Null will not impact ordering.

I hope it is clear now.

Cheers!!




回答2:


Try this one:

WHERE ...
ORDER BY 
   CASE pinSortColumn 
      WHEN 'FullName' THEN FULL_NAME 
      WHEN 'DateOfBirth' THEN DATE_OF_BIRTH
      WHEN 'Gender' THEN GEN_TR.GENDER   
   END;

However, I don't think you can use ASC, DESC is this way. You to create a dynamic query. For an OPEN ... FOR ... statement it is trivial:

sqlstr := 'SELECT * FROM (
      SELECT EMPLOYEE_ID, USERNAME, FULL_NAME, DATE_OF_BIRTH, EMP.GENDER_ID, GEN_TR.GENDER, EMP.WORK_TYPE_ID, WT_TR.WORK_TYPE, SALARY, EMAIL, PROFILE_IMAGE,
      ROW_NUMBER() OVER (ORDER BY EMPLOYEE_ID ASC) RN

      FROM EMPLOYEES EMP
      INNER JOIN GENDERS GEN ON EMP.GENDER_ID = GEN.GENDER_ID
      LEFT JOIN GENDERS_MLD GEN_TR ON GEN.GENDER_ID = GEN_TR.GENDER_ID AND GEN_TR.LANGUAGE = :pinLanguage
      INNER JOIN WORK_TYPES WT ON EMP.WORK_TYPE_ID = WT.WORK_TYPE_ID
      LEFT JOIN WORK_TYPES_MLD WT_TR ON WT.WORK_TYPE_ID = WT_TR.WORK_TYPE_ID AND WT_TR.LANGUAGE = :pinLanguage
    )
    WHERE RN BETWEEN (((:pinPage - 1) * :pinPageSize) + 1) AND (:pinPage * :pinPageSize) 
    ORDER BY '

CASE pinSortColumn 
   WHEN 'FullName' THEN sqlstr := sqlstr || 'FULL_NAME ';
   WHEN 'DateOfBirth' THEN sqlstr := sqlstr || 'DATE_OF_BIRTH ';
   WHEN 'Gender' THEN sqlstr := sqlstr || 'GEN_TR.GENDER ';
END CASE;   
sqlstr := sqlstr || pinSortOrder;

OPEN poutEmployeeCursor FOR sqlstr USING pinLanguage, pinLanguage, pinPage, pinPageSize, pinPage, pinPageSize;

Not in case you run Oracle 12c or newer you can use the Row Limiting Clause instead of dealing with row number.




回答3:


You can avoid all these duplicated cases. Multiply row number by -1 when descending order is required:

order by 
    case pinSortOrder when 'desc' then -1 else 1 end * 
    row_number() over (
      order by case pinSortColumn when 'FullName'    then full_name     end, 
               case pinSortColumn when 'Gender'      then gender        end, 
               case pinSortColumn when 'DateOfBirth' then date_of_birth end)  

dbfiddle demo

Also this way you do not have to convert data the same type, no need to use to_char.



来源:https://stackoverflow.com/questions/57545457/how-can-i-make-oracle-query-sort-order-dynamic

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!