从同一个表中的多个列中选择不同的值
Posted
技术标签:
【中文标题】从同一个表中的多个列中选择不同的值【英文标题】:Select distinct values from multiple columns in same table 【发布时间】:2012-07-03 09:29:15 【问题描述】:我正在尝试构建一个 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 语句,因为列来自同一个表?
【问题讨论】:
那个表结构让我感觉你的数据库没有标准化...... 您不需要在第一个查询中使用distinct
- union
会为您完成。
@gdoron:这些代码对应于各种名称,实际上可能会重复,即特定记录可能具有代码 1 和 2 的 BC 和 BC。代码 1 与 2 的指定也很重要。有用于各种代码的第三个查表表。不是最好的,但这就是我正在处理的问题。
@regulus 我用您查询的执行计划更新了我的答案,以便您进行比较。
【参考方案1】:
最好在您的问题中包含代码,而不是模棱两可的文本数据,以便我们都使用相同的数据。这是我假设的示例架构和数据:
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
过滤掉的任何重复项无论如何都会被 UNION
过滤掉.
这个查询在逻辑上等价于另外两个,但是冗余操作使得它的效率较低。在大型数据集上,我希望您的查询需要比这里的两个更长的时间才能返回结果集。不要相信我的话;在您自己的环境中进行实验以确保确定!
【讨论】:
我认为我在 SO 上读过的最佳答案之一。出色的细节和示例,以及测试结果。【参考方案2】:试试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 值。
【讨论】:
谢谢!似乎是我正在寻找的完美答案!【参考方案3】:在所需的行数据在类型、值等方面相似的任何地方都应用联合。无论您在同一个表中是否有列或从另一个表中检索列都没有关系,因为结果将保持不变(在上述之一中)答案已经提到)。
由于您不希望重复,因此使用 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
);
【讨论】:
【参考方案4】:如果你有两个以上的列,试试这个:
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
【讨论】:
以上是关于从同一个表中的多个列中选择不同的值的主要内容,如果未能解决你的问题,请参考以下文章