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

reg*_*lus 22 sql union distinct

我正在尝试构造一个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;
Run Code Online (Sandbox Code Playgroud)

例如,tbl_data如下:

 id   code_1    code_2
 ---  --------  ----------
 1    AB        BC
 2    BC        
 3    DE        EF
 4              BC
Run Code Online (Sandbox Code Playgroud)

对于上表,SQL查询应返回两列中的所有唯一非空值,即:AB,BC,DE,EF.

我对SQL很新.我上面的声明有效,但有没有更简洁的方法来编写这个SQL语句,因为这些列来自同一个表?

Iai*_*der 24

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

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');
Run Code Online (Sandbox Code Playgroud)

正如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;
Run Code Online (Sandbox Code Playgroud)

两列在同一个表中并不重要.即使列位于不同的表中,解决方案也是相同的.

如果您不喜欢两次指定相同过滤器子句的冗余,则可以在过滤之前将联合查询封装在虚拟表中:

SELECT code
FROM (
  SELECT code_1
  FROM tbl_data
  UNION
  SELECT code_2
  FROM tbl_data
) AS DistinctCodes (code)
WHERE code IS NOT NULL;
Run Code Online (Sandbox Code Playgroud)

我发现第二个的语法更难看,但它在逻辑上更整洁.但哪一个表现更好?

我创建了一个sqlfiddle,它演示了SQL Server 2005的查询优化器为两个不同的查询生成相同的执行计划:

查询优化器为两个查询生成此执行计划:两个表扫描,一个串联,一个不同的排序和一个选择.

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

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

DISTINCT子句使SQL Server 2005执行冗余排序操作.

DISTINCT子句使SQL Server 2005执行冗余排序操作,因为查询优化器不知道DISTINCT第一个查询中过滤掉的任何重复项都会被UNION后者过滤掉.

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


Joh*_*Woo 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
Run Code Online (Sandbox Code Playgroud)

UNION已经返回DISTINCT从组合查询值.