簡體   English   中英

從同一個表的多列中選擇不同的值

[英]Select distinct values from multiple columns in same table

我正在嘗試構建一個 SQL 語句,該語句從位於同一個表中的多個列返回唯一的非空值。

 SELECT distinct tbl_data.code_1 FROM tbl_data
      WHERE tbl_data.code_1 is not null
 UNION
 SELECT tbl_data.code_2 FROM tbl_data
      WHERE tbl_data.code_2 is not null;

比如tbl_data如下:

 id   code_1    code_2
 ---  --------  ----------
 1    AB        BC
 2    BC        
 3    DE        EF
 4              BC

對於上表,SQL 查詢應返回兩列中所有唯一的非空值,即:AB、BC、DE、EF。

我對 SQL 相當陌生。 我上面的語句有效,但是有沒有更簡潔的方法來編寫這個 SQL 語句,因為這些列來自同一個表?

最好在您的問題中包含代碼,而不是含糊不清的文本數據,以便我們都使用相同的數據。 這是我假設的示例架構和數據:

CREATE TABLE tbl_data (
  id INT NOT NULL,
  code_1 CHAR(2),
  code_2 CHAR(2)
);

INSERT INTO tbl_data (
  id,
  code_1,
  code_2
)
VALUES
  (1, 'AB', 'BC'),
  (2, 'BC', NULL),
  (3, 'DE', 'EF'),
  (4, NULL, 'BC');

正如Blorgbeard評論的那樣,解決方案中的DISTINCT子句是不必要的,因為UNION運算符消除了重復的行。 有一個不消除重復的UNION ALL運算符,但它在這里不合適。

在沒有DISTINCT子句的情況下重寫您的查詢是這個問題的一個很好的解決方案:

SELECT code_1
FROM tbl_data
WHERE code_1 IS NOT NULL
UNION
SELECT code_2
FROM tbl_data
WHERE code_2 IS NOT NULL;

兩列在同一個表中並不重要。 即使列在不同的表中,解決方案也是相同的。

如果您不喜歡兩次指定相同過濾器子句的冗余,您可以在過濾之前將聯合查詢封裝在虛擬表中:

SELECT code
FROM (
  SELECT code_1
  FROM tbl_data
  UNION
  SELECT code_2
  FROM tbl_data
) AS DistinctCodes (code)
WHERE code IS NOT NULL;

我發現第二個的語法更難看,但它在邏輯上更簡潔。 但是哪一個表現更好呢?

我創建了一個sqlfiddle ,它演示了 SQL Server 2005 的查詢優化器為兩個不同的查詢生成相同的執行計划:

查詢優化器為兩個查詢生成這個執行計划:兩個表掃描、一個串聯、一個不同的排序和一個選擇。

如果 SQL Server 為兩個查詢生成相同的執行計划,那么它們實際上和邏輯上是等效的。

將上述內容與您問題中查詢的執行計划進行比較:

DISTINCT 子句使 SQL Server 2005 執行冗余排序操作。

DISTINCT子句使 SQL Server 2005 執行冗余排序操作,因為查詢優化器不知道在第一個查詢中被DISTINCT過濾掉的任何重復項無論如何都會被UNION過濾掉。

此查詢在邏輯上與其他兩個查詢等效,但冗余操作使其效率較低。 在大型數據集上,我希望您的查詢返回結果集所需的時間比此處的兩個更長。 不要相信我的話; 在您自己的環境中進行實驗以確保!

嘗試像SubQuery這樣的東西:

SELECT derivedtable.NewColumn
FROM
(
    SELECT code_1 as NewColumn FROM tbl_data 
    UNION
    SELECT code_2 as NewColumn FROM tbl_data 
) derivedtable
WHERE derivedtable.NewColumn IS NOT NULL

UNION已經從組合查詢中返回DISTINCT值。

如果您有兩個以上的列,請嘗試此操作:

CREATE TABLE #temptable (Name1 VARCHAR(25),Name2 VARCHAR(25))

INSERT INTO #temptable(Name1, Name2)
  VALUES('JON', 'Harry'), ('JON', 'JON'), ('Sam','harry')

SELECT t.Name1+','+t.Name2 Names  INTO #t FROM #temptable AS tSELECT DISTINCT ss.value FROM #t AS t
  CROSS APPLY STRING_SPLIT(T.Names,',') AS ss

聯合適用於所需行數據在類型、值等方面相似的任何地方。 無論您在同一個表中還是另一個表中有列都可以檢索,因為結果將保持不變(在上述答案之一中已經提到盡管)。

由於您不想要重復項,因此使用 UNION ALL 毫無意義,並且使用 distinct 完全沒有必要,因為 union 提供了不同的數據

可以創建視圖將是最佳選擇,因為視圖是表的虛擬表示。 然后可以在創建的視圖上整齊地進行修改

Create VIEW getData AS 
(
  SELECT distinct tbl_data.code_1 
    FROM tbl_data
    WHERE tbl_data.code_1 is not null
  UNION
  SELECT tbl_data.code_2 
    FROM tbl_data
    WHERE tbl_data.code_2 is not null
);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM