DISTINCT ORDER BY 是兩個常用Oracle SQL文法的SQL子句。其中, DISTINCT 用於消除查詢結果中的重複記錄, ORDER BY 用於對查詢結果進行排序。當這兩個子句結合使用時,需要注意它們的文法和執行順序。本文將詳細介紹如何在Oracle SQL文法使用 DISTINCT ORDER BY ,並通過樣本協助您更好地理解和應用。

基本文法

SELECT DISTINCT column1, column2, ...
FROM table_name
WHERE condition
ORDER BY column1 [ASC|DESC], column2 [ASC|DESC], ...;
  • SELECT DISTINCT:選擇唯一不同的記錄,消除重複行。

  • FROM:指定查詢的資料表。

  • WHERE:可選,指定查詢條件。

  • ORDER BY:對結果集進行排序,可以指定一個或多個列,並選擇升序  ( ASC )  或降序  ( DESC )。

工作原理

在SQL查詢中, DISTINCT 會在 ORDER BY 之前執行,即先篩選出唯一的記錄,然後再對這些唯一記錄進行排序。

使用樣本

假設有一個名為 employees 的表,結構如下:

CREATE TABLE employees (
    employee_id INT PRIMARY KEY , -- 員工唯一標識
    first_name VARCHAR(50) NOT NULL,           -- 員工名字
    last_name VARCHAR(50) NOT NULL,            -- 員工姓氏
    department VARCHAR(50),                    -- 部門編號
    salary DECIMAL(10, 2) CHECK (salary > 0)   -- 薪資
INSERT INTO employees VALUES (1, 'John', 'Doe', 'Sales', 5000);
INSERT INTO employees VALUES (2, 'Jane', 'Smith', 'Marketing', 6000);
INSERT INTO employees VALUES (3, 'John', 'Doe', 'Sales', 5000);
INSERT INTO employees VALUES (4, 'Alice', 'Johnson', 'IT', 7000);
INSERT INTO employees VALUES (5, 'Bob', 'Brown', 'Sales', 5000);
  • 選擇唯一的部門並按名稱排序。

    SELECT DISTINCT DEPARTMENT
    FROM employees
    ORDER BY DEPARTMENT ASC;

    返回結果如下:

     department 
    ------------
     Marketing
     Sales
    (3 rows)
  • 選擇唯一的工資,並按工資降序排序。

    SELECT DISTINCT SALARY
    FROM employees
    ORDER BY SALARY DESC;

    返回結果如下:

     salary  
    ---------
     7000.00
     6000.00
     5000.00
    (3 rows)
  • 選擇唯一的姓名組合并排序。

    SELECT DISTINCT FIRST_NAME, LAST_NAME
    FROM employees
    ORDER BY FIRST_NAME ASC, LAST_NAME ASC;

    返回結果如下:

    說明

    即使有多條記錄的 FIRST_NAME LAST_NAME 相同, DISTINCT 只會返回一條唯一的組合。

     first_name | last_name 
    ------------+-----------
     Alice      | Johnson
     Bob        | Brown
     Jane       | Smith
     John       | Doe
    (4 rows)

注意事項

  • ORDER BY中的列

    在使用 ORDER BY 時,所指定的列必須出現在 SELECT 子句中。如果在 ORDER BY 中引用不在SELECT中的列, PolarDB 將報錯。

    錯誤樣本:

    SELECT DISTINCT FIRST_NAME
    FROM employees
    ORDER BY LAST_NAME ASC;

    報錯如下:

    ERROR:  for SELECT DISTINCT, ORDER BY expressions must appear in select list

    然而,由於Oracle的相容性原因,可以通過啟用參數polar_enable_distinct_orderby_new_column來合法引用不在SELECT語句中的列。該用法使用步驟如下:

    1. 啟用polar_enable_distinct_orderby_new_column參數。

      說明

      PolarDB PostgreSQL版 Oracle文法相容 2.0 在核心小版本2.0.14.26.0新增 polar_enable_distinct_orderby_new_column 參數。若叢集的核心小版本低於該版本且需要合法引用不在SELECT語句中的列,請將核心小版本升級到2.0.14.26.0或以上版本。查詢和升級核心小版本,請參見 版本管理

    2. ORDER BY 中引用不在 SELECT 中的列。

    3. 查詢末尾添加 FETCH FIRST X rows ONLY LIMIT 欄位。

      SELECT DISTINCT FIRST_NAME
      FROM employees
      ORDER BY LAST_NAME ASC
      FETCH FIRST 2 rows ONLY;
  • 使用別名

    支援為 SELECT 中的列指定別名,並在 ORDER BY 中使用這些別名。

    SELECT DISTINCT FIRST_NAME AS FN
    FROM employees
    ORDER BY FN ASC;
  • ORDER BY列的位置

    支援使用列的位置來排序,例如 ORDER BY 1 表示按 SELECT 中第一個列排序。

    SELECT DISTINCT FIRST_NAME, LAST_NAME
    FROM employees
    ORDER BY 1 ASC;

進階用法

  • 結合 WHERE 子句

    在使用 DISTINCT ORDER BY 時,可以添加 WHERE 子句以篩選特定記錄。

    樣本:

    SELECT DISTINCT DEPARTMENT
    FROM employees
    WHERE SALARY > 5000
    ORDER BY DEPARTMENT ASC;

    返回結果如下:

     department 
    ------------
     Marketing
    (2 rows)
  • 使用子查詢

    在某些複雜的查詢情境中,可以使用子查詢結合 DISTINCT ORDER BY

    樣本:

    假設需要先找出工資最高的每個部門,然後按部門名稱排序:

    SELECT DEPARTMENT, MAX(SALARY) AS MAX_SALARY
    FROM employees
    GROUP BY DEPARTMENT
    ORDER BY DEPARTMENT ASC;

    返回結果如下:

     department | max_salary 
    ------------+------------
     IT         |    7000.00
     Marketing  |    6000.00
     Sales      |    5000.00
    (3 rows)
  • 結合視窗函數

    當需要在 DISTINCT ORDER BY 的基礎上進行更複雜的資料分析時,可以結合使用視窗函數。

    樣本:

    選出每個部門中工資最高的員工,並按薪資降序排列。

    SELECT DISTINCT DEPARTMENT, FIRST_NAME, LAST_NAME, SALARY
    FROM (
        SELECT DEPARTMENT, FIRST_NAME, LAST_NAME, SALARY,
               ROW_NUMBER() OVER (PARTITION BY DEPARTMENT ORDER BY SALARY DESC) AS rn
        FROM employees
    WHERE rn = 1
    ORDER BY SALARY DESC;

    返回結果如下:

     department | first_name | last_name | salary 
    ------------+------------+-----------+--------
     IT         | Alice      | Johnson   |   7000
     Marketing  | Jane       | Smith     |   6000
     Sales      | John       | Doe       |   5000
    (3 rows)

常見錯誤與調試

使用不在WHERE中的列進行排序

ORDER BY中的列 描述,在 ORDER BY 使用未在 SELECT 子句中的列會導致錯誤。確保 ORDER BY 中的所有列都出現在 SELECT 中,或者使用別名或列位置。

說明

如果啟用 polar_enable_distinct_orderby_new_column 參數,並滿足 FETCH FIRST X rows only ,這種情況視為合法,此時 DISTINCT 將隱式引用 ORDER BY 中的列。

混淆DISTINCT的作用範圍

DISTINCT 適用於 SELECT 子句中列的整個組合,而不僅僅是單個列。因此,使用多個列的 SELECT DISTINCT 將基於所有指定列的組合來消除重複。

樣本:

SELECT DISTINCT FIRST_NAME, DEPARTMENT
FROM employees
ORDER BY FIRST_NAME ASC;

以上SQL語句將消除 FIRST_NAME DEPARTMENT 組合中的重複記錄,而不僅僅是 FIRST_NAME

效能最佳化

在處理巨量資料集時,使用 DISTINCT ORDER BY 可能會對查詢效能產生影響。以下是一些最佳化建議:

  • 索引最佳化:為 WHERE DISTINCT ORDER BY 使用的列建立適當的索引,加快查詢速度。

  • 減少返回的列數:只選擇必要的列,避免不必要的資料處理。

  • 使用分區:對大表進行分區,可以提高查詢效率。

  • 查詢計劃分析:使用 EXPLAIN PLAN 分析查詢執行計畫,發現潛在的效能瓶頸。

樣本:

使用索引最佳化。

-- 建立索引以最佳化 DEPARTMENT 列的查詢
CREATE INDEX idx_employees_department ON employees(DEPARTMENT);

總結

DISTINCT ORDER BY PolarDB SQL中功能強大的工具,用於消除重複記錄和對結果集進行排序。瞭解其工作原理、正確文法及常見使用情境,有助於您編寫高效且準確的查詢。在實際應用中,根據具體需求合理組合這兩個子句,並結合其他SQL功能,可以實現複雜的資料處理與分析任務。