【问题标题】:SELECT DISTINCT with composite keySELECT DISTINCT 与复合键
【发布时间】:2017-03-27 23:51:14
【问题描述】:

这是对我遇到的问题的简化,但使用此示例我想获取给定客户的所有产品记录。 给客户可能有很多订单,有些订单可能是同一产品我不想拉回重复的产品。 产品表上还有一个复合键。

在理想情况下,这很简单,下面的 Query 就可以完成这项工作。但是,由于该表包含一个 nText 列,SQL Server 抱怨“ntext 数据类型不能选择为 DISTINCT,因为它不可比较。”

SELECT distinct p.idA, p.idB, p.descriptionNTEXT
FROM p product, o order, c customer
WHERE o.productID = p.idA AND o.subProductID = p.idB AND o.customerID = c.ID

我想将其重新构建为类似

SELECT p1.idA, p1.idB, p1.descriptionNTEXT
FROM   p1 product
WHERE (p1.idA, p1.idB) IN
   (
       SELECT p.idA, p.idB
       FROM p product, o order, c customer
       WHERE o.productID = p.idA AND o.subProductID = p.idB AND o.customerID = c.ID
   )

How do I (or can I) SELECT DISTINCT on multiple columns?

但是这种方法在 SQL Server 上不起作用

有什么想法吗?

理想情况下,我需要一个可移植的解决方案,至少可以在 SQLServer、MySQL 和 Oracle 上运行。但是 DB 特定的解决方案总比没有好!

以下数据大致显示了我想要的。

Customer
ID name
1  Fred

Order
ID  CustomerID productID subProductID
10  1          100       200
11  1          100       200
12  1          100       200
13  1          101       201

Product
IDA  IDB descriptionNTEXT
100  200 'product 1'
101  201 'product 2'    
102  203 'product 3'    

Expected Result
IDA  IDB descriptionNTEXT
100  200 'product 1'
101  201 'product 2'    

【问题讨论】:

  • 添加一些示例表数据和预期结果 - 以及格式化文本。

标签: sql sql-server select distinct composite-primary-key


【解决方案1】:

将 NTEXT 转换为 NVARCHAR(MAX)

SELECT distinct p.idA, p.idB, cast (p.descriptionNTEXT as nvarchar(max))
FROM p product, o order, c customer
WHERE o.productID = p.idA AND o.subProductID = p.idB AND o.customerID = c.ID

重要! ntext、text 和 image 数据类型将在 SQL Server 的未来版本。避免在 new 中使用这些数据类型 开发工作,并计划修改当前使用的应用程序 他们。请改用 nvarchar(max)、varchar(max) 和 varbinary(max)。

https://msdn.microsoft.com/en-us/library/ms187993.aspx


nvarchar [ ( n | max ) ] 可变长度 Unicode 字符串数据。 n 定义字符串长度,可以是 1 到 4,000 之间的值。最大限度 表示最大存储大小为 2^31-1 字节(2 GB)。这 存储大小(以字节为单位)是输入数据实际长度的两倍 + 2 个字节。 nvarchar 的 ISO 同义词是国家字符变化和国家字符变化。

https://msdn.microsoft.com/en-us/library/ms186939.aspx

【讨论】:

  • 谢谢,我想如果在旧 SQL 版本上超过 4000/8000 个字符,那会截断描述?它还需要处理 blob。不幸的是,避免使用这些类型不是一个选项,因为这是一个将在 3rd 方数据库上运行的工具。但是很高兴知道它们被替换了,它们总是问题和不兼容的根源。
  • @Sproty,nvarchar(max) 限制为 2G(请参阅编辑后的答案)。对于 BLOB 使用 varbinary(max) msdn.microsoft.com/en-us/library/ms188362.aspx
  • 是任何唯一IDA IDB组合所赋予的唯一性吗?这似乎是建立不同行的好方法 - 您的示例 SQL 似乎在合理的行上,除了您不能将 IN 用于两个字段 - 但您可以切换到 EXISTS (这将适用于零个、1 个或多个字段) - 那么您也许不需要担心转换 BLOB、ntext 等 - 使用产品描述来确定唯一性可能不是最好的方法。
  • @Sprotty “用于在 3rd 方数据库上运行的工具” - SELECT DISTINCT SEVERAL_GIGABYTES?问题不在于类型。问题在于解决方案。你必须找到不同的方法来解决你的任务。
  • @Ivan - 我认为他可能距离更好的解决方案还有 1 毫米的距离 - 描述对于任何唯一的 idA 和 idB 来说可能都是独一无二的 - 他只是想列出唯一的 idA 和 idB 组合
【解决方案2】:

查看您的代码,您似乎想在多个字段上使用 IN - 这可以通过 EXISTS 实现 - 它询问指定的查询是否返回任何行 - 因此根据您的查询,它可能类似于

SELECT p1.idA, p1.idB, p1.descriptionNTEXT
FROM   p1 product
WHERE EXISTS
   (
       SELECT 1
       FROM p product, o order, c customer
       WHERE o.productID = p.idA AND o.subProductID = p.idB AND o.customerID = c.ID 
             AND p1.idA = p.ida 
             AND p1.idB = p.idb
   )

【讨论】:

  • 谢谢,这看起来像是对原始查询的干净重构,并且似乎是不会给查询带来巨大开销的普通 SQL。
  • 不完全是我的用例,但WHERE EXISTS( SELECT 1 ...) 的想法引导我走向了正确的方向。非常聪明:)
【解决方案3】:

你可以试试这个,而不用把它转换成另一种类型

SELECT p1.idA, p1.idB, p1.descriptionNTEXT
from product p1 where p1.IDA in( SELECT Distinct p.idA FROM  product p,order o,customer c WHERE o.productID = p.idA AND o.subProductID = p.idB AND o.customerID = c.ID)

【讨论】:

  • 这似乎适用于我提供的有限测试数据,但如果 IDA 使用不同的 IDB 值重复,则无法按预期工作。
【解决方案4】:

先做 distinct,然后加入产品。

select p.*
    from (
        select distinct CustomerID, productID, subProductID
        from [Order]
    ) do
    join Product p on p.productID = do.IDA and p.subProductID = do.IDB

【讨论】:

  • 我认为这看起来是一个合理的解决方案,尽管语法可能不是 SQL SERVER - 但是问题一般都提到了 DB - 也许在被否决时可以用评论来完成?
  • @Cato 我真的不希望这个确切的查询能在 SQL Server 中工作,但我相信它应该在原则上工作。我的查询的哪些部分不适用于 SQL Server?
  • 可能是 'Product p on (p.productID, p.subProductID) = (do.IDA, do.IDB)' 部分,或者可能是我以前从未见过,或者它是较新的SQL版本
  • @Cato 事实上,我在谷歌搜索后了解到,MS SQL Server 不支持元组比较。我修复了查询。
猜你喜欢
  • 2017-01-25
  • 2015-03-26
  • 2017-07-23
  • 1970-01-01
  • 1970-01-01
  • 2023-03-10
  • 2011-12-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多