为啥“SELECT DISTINCT a, b FROM...”返回的记录少于“SELECT DISTINCT A + '|' + B 来自...”?

Posted

技术标签:

【中文标题】为啥“SELECT DISTINCT a, b FROM...”返回的记录少于“SELECT DISTINCT A + \'|\' + B 来自...”?【英文标题】:Why does "SELECT DISTINCT a, b FROM..." return fewer records than "SELECT DISTINCT A + '|' + B FROM..."?为什么“SELECT DISTINCT a, b FROM...”返回的记录少于“SELECT DISTINCT A + '|' + B 来自...”? 【发布时间】:2011-03-30 10:51:43 【问题描述】:

我有一个查询,它选择了一堆与客户姓名和地址相关的字段,但归结为:

SELECT DISTINCT a, b, c, ... FROM big_dumb_flat_table

它返回一堆记录 (10986590)。当我替换选择列表中的逗号以将其格式化为管道分隔的连接字符串时:

SELECT DISTINCT a + '|' + b + '|' + c + '|' + ... FROM big_dumb_flat_table

它又返回了 248 条记录。我已经向自己保证,在任何领域都没有管道可能会破坏返回集的保真度。这是怎么回事?

【问题讨论】:

你能看看你用SELECT a,b,c... FROM ... GROUP BY a,b,c...得到了什么,然后把它编辑成你的问题吗? (因为DISTINCT 在技术上是一个(非常方便的)hack) 还将 count(*) 添加到查询中,看看有什么效果 我希望使用连接的查询返回更少条记录,因为如果任何值是null,您将得到null结果。 马克,关于计数你想知道什么?它们从 1 到低数百不等。但这就是应该的(在完全非规范化的数据源中,“应该”是一件有趣的事情)。 查询运行,将 DISTINCT 替换为 GROUP BY 返回相同的数字。 【参考方案1】:

尾随空格可能会导致这种情况。对于字符串比较,这些会被忽略。

CREATE TABLE #T
(
a varchar(10),
b varchar(10),
c varchar(10)
)

INSERT INTO #T
SELECT 'a ' as a, 'b' as b, 'c ' as c union all
SELECT 'a' as a, 'b' as b, 'c ' as c

SELECT DISTINCT a, b, c  
FROM #T /*1 result*/

SELECT DISTINCT a + '|' + b + '|' + c + '|'   
FROM #T /*2 results*/


SELECT DISTINCT LTRIM(RTRIM(a)) + '|' + LTRIM(RTRIM(b)) + '|' +
                LTRIM(RTRIM(c)) + '|'   
FROM #T /*1 result*/

【讨论】:

整洁。我运行了您第一次发布的缩写代码,以亲眼看到您是对的,现在我正在测试两个查询,所有字段都包含在 ltrim(rtrim()) 中。那应该可以解决这个问题吧? 他也应该处理空值。 @clweeks - 这些列可以为空吗?如果是这样,您需要记住使用 COALESCE 或其他方式处理 Null。 (注意:如果这只是一项一次性任务,您可以执行 SET CONCAT_NULL_YIELDS_NULL OFF 但不能用于生产代码!) 所有字段上的 LTRIM(RTRIM()) 导致计数匹配。有些列可以为空,但没有任何空值。非常感谢!【参考方案2】:

我能想到的任何场景都不会为您带来更多记录,只会更少。我会通过只选择 + '|' 来简化查询,然后随时添加更多列。

【讨论】:

以上是关于为啥“SELECT DISTINCT a, b FROM...”返回的记录少于“SELECT DISTINCT A + '|' + B 来自...”?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 DataGridView 上的 DoubleBuffered 属性默认为 false,为啥它受到保护?

为啥需要softmax函数?为啥不简单归一化?

为啥 g++ 需要 libstdc++.a?为啥不是默认值?

为啥或为啥不在 C++ 中使用 memset? [关闭]

为啥临时变量需要更改数组元素以及为啥需要在最后取消设置?

为啥 CAP 定理中的 RDBMS 分区不能容忍,为啥它可用?