从同一个表中的多个列中选择不同的值

时间:2012-07-02 23:35:43

标签: sql distinct union

我正在尝试构造一个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语句,因为这些列来自同一个表?

4 个答案:

答案 0 :(得分:22)

最好在问题中包含代码,而不是模糊的文本数据,以便我们都使用相同的数据。以下是我假设的示例模式和数据:

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的查询优化器为两个不同的查询生成了相同的执行计划:

The query optimizer produces this execution plan for both queries: two table scans, a concatenation, a distinct sort, and a select.

如果SQL Server为两个查询生成相同的执行计划,那么它们实际上与逻辑上等效。

将上述内容与您问题中的查询执行计划进行比较:

The DISTINCT clause makes SQL Server 2005 perform a redundant sort operation.

DISTINCT子句使SQL Server 2005执行冗余排序操作,因为查询优化器不知道第一个查询中DISTINCT过滤掉的任何重复项都会被{过滤掉无论如何,{1}}。

此查询在逻辑上等同于其他两个,但冗余操作使其效率降低。在大型数据集上,我希望您的查询返回结果集所需的时间比这里的两个要长。不要相信我的话;在你自己的环境中进行实验以确保!

答案 1 :(得分:5)

尝试类似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 值。

答案 2 :(得分:0)

如果您有两个以上的列,请尝试

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

答案 3 :(得分:0)

在需要的行数据在类型,值等方面相似的情况下应用联合。在同一表中检索列或从中检索另一列都无关紧要,因为结果将保持不变(在上述情况之一中)答案已经提到了。)

因为您不希望重复,所以使用UNION ALL是没有意义的,并且因为UNIT会提供不同的数据,所以完全不必使用distinct

可以创建视图将是最佳选择,因为视图是表的虚拟表示形式。然后可以对创建的视图进行整齐的修改

       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);