选择一列不重复的SQL语句

14

增加:需要与SQL Server 2000和2005一起使用,因此必须在两个版本上运行。此外,value_rk不是数字/整数(错误:min操作符的操作数据类型uniqueidentifier无效)

当我不关心返回的其他列时,有没有一种方法可以进行单列“DISTINCT”匹配?例如:

**Table**
Value A, Value L, Value P
Value A, Value Q, Value Z

基于第一行中的内容(值A),我需要仅返回其中一行。 我仍然需要第二列和第三列的结果(第二列实际上应该在所有情况下都匹配,但第三列是唯一键,我至少需要其中一个)。

这是我目前所拥有的,尽管显然它不起作用:

SELECT value, attribute_definition_id, value_rk
FROM attribute_values
WHERE value IN (
    SELECT value, max(value_rk)
    FROM attribute_values
)
ORDER BY attribute_definition_id

我在使用ColdFusion工作,因此如果有简单的解决方法,我也可以考虑。 我试图限制或按“value”分组第一列。 value_rk是我的大问题,因为每个值都是唯一的,但我只需要一个。

注意:value_rk不是数字,因此这不起作用。

更新:我有一个可行的版本,它可能比纯SQL版本慢得多,但说实话,任何工作的东西现在都比没有好。 它从第一个查询的结果中取出数据,执行第二个查询,除了将结果限制为一个之外,还获取与匹配的值相匹配的value_rk。 就像这样:

<cfquery name="queryBaseValues" datasource="XXX" timeout="999">
    SELECT DISTINCT value, attribute_definition_id
    FROM attribute_values
    ORDER BY attribute_definition_id
</cfquery>

<cfoutput query="queryBaseValues">
    <cfquery name="queryRKValue" datasource="XXX">
        SELECT TOP 1 value_rk
        FROM attribute_values
        WHERE value = '#queryBaseValues.value#'
    </cfquery>
    <cfset resourceKey = queryRKValue.value_rk>
    ...

所以,这就是在 ColdFusion 中选择单个不同列的方法。任何关于纯 SQL Server 2000/2005 的建议仍然非常受欢迎 :)


你能澄清一下你需要什么吗?是任何行,但每个值只有一行?还是具有最大value_rk值的值所在的行?我不确定我理解你的意图。 - tvanfosson
注意:value_rk不是一个数字,因此这个方法行不通。这与你的查询失败无关。你没有提到你使用的RDBMS,但在Oracle中,你可以在字符列上使用MAX函数。 - Mark Brady
MS SQL 也可以在非数字列上使用 MAX。 - BradC
除非您还使用ORDER BY,否则使用TOP是不可靠的。 在没有指定顺序的情况下,SQL不能保证行将以任何顺序返回。 - Bill Karwin
很不幸,没有真正的方法可以确定哪个是最老的或最新的,因为数据库没有按照这种方式设置(我在这方面没有选择权)。项目部分昨天就要交了,我已经完成了它,虽然不是理想的情况,但总比完全没有交付好:/ - Organiccat
显示剩余4条评论
11个回答

11

这可能有效:

SELECT DISTINCT a.value, a.attribute_definition_id, 
  (SELECT TOP 1 value_rk FROM attribute_values WHERE value = a.value) as value_rk
FROM attribute_values as a
ORDER BY attribute_definition_id

..未经测试。


9
SELECT a1.value, a1.attribute_definition_id, a1.value_rk
FROM attribute_values AS a1
  LEFT OUTER JOIN attribute_values AS a2
    ON (a1.value = a2.value AND a1.value_rk < a2.value_rk)
WHERE a2.value IS NULL
ORDER BY a1.attribute_definition_id;

换句话说,找到行 a1,使得没有行 a2 满足与之相同的 value 值且 value_rk 值更大。

这是一个很好的解决方案,因为它可以与大多数(全部?)关系型数据库管理系统一起使用。我已经被PostgreSQL的DISTINCT ON宠坏了,这很容易输入,但是非标准的,在SQL Server等其他数据库中没有实现。 - Sam

8
这应该适用于PostgreSQL,我不知道您使用哪个数据库管理系统。
SELECT DISTINCT ON (value)
  value, 
  attribute_definition_id, 
  value_rk
FROM 
  attribute_values
ORDER BY
  value, 
  attribute_definition_id

PostgreSQL文档


4
这里唯一的问题是MS-SQL不支持DISTINCT ON,只能在所有被选中的列中使用DISTINCT... - Stefan Steiger

2

如果你愿意使用表变量,你可以像这样在单个数据库调用中完成所有操作:

DECLARE @attribute_values TABLE (value int, attribute_definition_id int, value_rk uniqueidentifier)

INSERT INTO @attribute_values (value)
SELECT DISTINCT value FROM attribute_values

UPDATE @attribute_values
SET attribute_definition_id = av2.attribute_definition_id,
    value_rk = av2.value_rk
FROM @attribute_values av1
INNER JOIN attribute_values av2 ON av1.value = av2.value

SELECT value, attribute_definition_id, value_rk FROM @attribute_values

你实际上正在创建一个记录集,其中填充了“value”唯一值的表,并且让SQL Server只使用主表中的一项匹配项来填补空缺。

编辑以添加:此语法在cfquery中可以很好地工作。


2

这是您在寻找的内容吗?

SELECT value, attribute_definition_id, value_rk
FROM attribute_values av1
WHERE value_rk IN (
        SELECT max(value_rk)
        FROM attribute_values av2
        WHERE av2.value = av1.value
)
ORDER BY attribute_definition_id

如果value_rk是唯一的,这应该可以工作。

2

好的,这是我的假设:

标准 SQL Server

value_rk不是数值,但value和attribute_definition_id是数值。

SELECT value_rk, MIN(value) as value, MIN(attribute_definition_id) as attribute_definition_id
FROM attribute_values
GROUP BY value_rk
ORDER BY MIN(attribute_definition_id)

如果其中一个字段不是数字,那就需要更多的思考 - 请告诉我们。

1
SELECT value, attribute_definition_id, value_rk
FROM attribute_values
WHERE value, value_rk IN (
        SELECT value, max(value_rk)
        FROM attribute_values
        GROUP BY value
)
ORDER BY attribute_definition_id

未经测试!


我的错,我没有自己测试就发布了,我更新了值 value_rk 不是一个数字(最大/最小值无法在其上运作)。 - Organiccat
max/min 函数可以用于 SQL2005 中的 varchar 值。您使用的是什么数据库? - BradC
实际测试是在2005上进行的,但生产服务器是2000。当我尝试在其上运行min/max时(已添加到OP帖子的顶部),会出现数据类型不匹配的错误。 - Organiccat
OP的帖子就像PIN码或社会安全号码。 - Mark Brady
它在你的场景中无法工作,因为IN需要一个单列值列表。WHERE foo in (SELECT bar, max(baz) ...)是错误的,无论baz是否为数字。 - Mark Brady
我尝试将max与顶部的select一起移动,但结果相同。由于某种原因,在WHERE部分中使用max实际上没有引发错误,但也没有影响结果。 - Organiccat

1

我不确定我是否完全理解你的设置,但是否可以尝试这样做:

SELECT value, attribute_definition_id, value_rk
FROM attribute_values
GROUP BY value
ORDER BY attribute_definition_id;

再次说明,我不确定您要限制哪一列,以及您想要如何限制它。


0

我想

SELECT DISTINCT a.value, a.attribute_definition_id, 
(SELECT TOP 1 value_rk FROM attribute_values WHERE value = a.value) as value_rk
FROM attribute_values as a
ORDER BY attribute_definition_id

工作了


0
正如John Fiala所指出的那样,在SQL Server中,当您想在一组列的子集上执行“distinct”操作时,规范答案是使用group by子句。为什么这是正确的规范答案呢?因为您想要引入不属于您的“distinct”组的列。对于这些附属列,您想要拉取哪些行呢?使用group by子句并为这些附属列定义聚合函数可以使您的查询表现良好,因为现在您知道如何获取这些附属列。本文提供了更多细节:

http://weblogs.sqlteam.com/jeffs/archive/2007/10/12/sql-distinct-group-by.aspx

SELECT value_rk, MIN(value) as value, 
MIN(attribute_definition_id) as attribute_definition_id
FROM attribute_values
GROUP BY value_rk

此外,值得注意的是,MIN和MAX适用于文本和其他几种非数值类型的数据。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接