我正在尝试构造一个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语句,因为这些列来自同一个表?
答案 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的查询优化器为两个不同的查询生成了相同的执行计划:
如果SQL Server为两个查询生成相同的执行计划,那么它们实际上与逻辑上等效。
将上述内容与您问题中的查询执行计划进行比较:
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);