【问题标题】:SQL Server: How do I maintain data integrity using aggregate functions with group by?SQL Server:如何使用带有 group by 的聚合函数来维护数据完整性?
【发布时间】:2012-04-10 12:28:46
【问题描述】:

这是我的问题:如何使用带有 group by 的聚合函数来保持记录完整性?

为了进一步解释,这里有一个例子。

我有一个包含以下列的表:(将其视为“订单”表)

Customer_Summary (first 10 char of name + first 10 char of address)
Customer_Name
Customer_Address
Customer_Postal Code
Order_weekday

每个“订单”只有一行,有很多行具有相同的客户名称、地址和摘要。

我要做的是显示客户的姓名、地址和邮政编码,以及他们在每个工作日下的订单数量,按客户的摘要分组。

所以数据应该是这样的:

Summary             | Name        | Address    | PCode | Monday | Tuesday | Wednesday | Thursday | Friday

test custntest addre|test custname|test address|123456 | 1      | 1       | 1         | 1        | 1

我只想将类似客户摘要的记录分组在一起,但显然我希望显示一个姓名、地址和邮政编码。我现在正在使用 min(),所以我的查询看起来像:

SELECT Customer_Summary, min(customer_name), min(customer_address), min(customer_postal_code) 
FROM Order
Group by customer_summary

我已经省略了我的工作日逻辑,因为我认为没有必要。

我的问题是 - 这些客户中有一些具有相同客户摘要的客户具有不同的地址和邮政编码。

所以我可能有两个客户,看起来像:

test custntest addre|test custname |test address |323456|

test custntest addre|test custname2|test address2|123456|

使用分组依据,我的查询将返回以下内容:

test custntest addre|test custname |test address |123456|

由于我使用的是 min,它将为我提供所有字段的最小值,但不一定来自同一记录。所以我在这里失去了我的记录完整性 - 查询返回的地址和名称与邮政编码不正确匹配。

那么,在使用 group by 子句时,如何维护非分组字段的数据完整性?

希望我解释得足够清楚,并提前感谢您的帮助。

编辑:已解决。谢谢大家!

【问题讨论】:

  • 所以您想进行汇总,但是当客户拥有多个地址时您想怎么做?你能举一个你想要最终得到的结果集的例子吗?
  • 客户信息应该在其自己的表中 - 如果您不断在Orders 表中复制它,您将永远无法保证任何数据完整性/数据质量.....
  • 我确实在上面提供了一个例子——就选择哪个地址而言,唯一重要的是它必须与姓名和邮政编码相匹配。我使用 min 是因为它最简单,但正如我上面演示的那样,我以这种方式失去了记录的完整性。 @marc:我意识到这一点;不幸的是,这个数据库结构已经给了我,我无法改变它。我意识到这可能需要我在这个问题上咬紧牙关,但我希望有一个我没有想到的解决方案......

标签: sql sql-server sql-server-2005


【解决方案1】:

您始终可以使用ROW_NUMBER 代替GROUP BY

WITH A AS (
    SELECT Customer_Summary, customer_name, customer_address, customer_postal_code,
        ROW_NUMBER() OVER (PARTITION BY Customer_Summary ORDER BY customer_name, customer_address) AS rn
    FROM Order
)
SELECT Customer_Summary, customer_name, customer_address, customer_postal_code
FROM A
WHERE rn = 1

然后,您可以在 ORDER BY 子句中随意订购要使用​​的客户。目前我是按名称订购,然后按地址订购。

编辑:

我的解决方案符合您的要求。但我肯定同意其他人的观点:如果允许您更改数据库结构,这将是一个好主意……您不是(看到您的评论)。好吧,那么 ROW_NUMBER() 是个好方法。

【讨论】:

  • 这看起来很有趣 - 让我试一试。
  • 到目前为止似乎工作正常。这实际上是一个更大的查询的一小部分,所以我将尝试将它插入到它的其余部分,并希望它仍然有效。还有一个需要注意的是,性能必须是可以接受的——我尝试使用自定义函数进行查找,但巨大的开销扼杀了该计划。
  • @Mansfield:根据我的经验,与 GROUP BY 相比,ROW_NUMBER() 不会造成任何巨大的开销。我也在使用大桌子。我想你会发现它的性能相当不错,尤其是与自定义函数相比!
  • @Mansfield:如果您在“插入”时遇到问题,我可以尝试提供帮助。如果你不习惯 Common Table Expressions(WITH 子句),我可以指出它需要在语句中出现,并且前面的语句必须以分号结尾
  • 我熟悉 CTE。再给我几分钟玩它。
【解决方案2】:

我认为你需要重新考虑你的结构。

理想情况下,您应该拥有一个具有唯一 ID 的 Customer 表。然后,您将在 Order 表中使用该唯一 ID。那么你就不需要你正在使用的奇怪的“前 10 个字符”方法了。相反,您只需按 Customer 表中的唯一 ID 进行分组。

您甚至还可以有一个单独的地址表,将每个地址与客户相关联,其中包含多行(字段将它们标记为家庭地址、送货地址、帐单地址等)

这样您就可以将客户信息与地址信息和订单信息分开。这样,如果客户更改姓名(婚姻)或地址(搬家),您就不会破坏您的数据 - 一切都与 ID 相关,而不是数据本身。

[这种关系称为外键。]

【讨论】:

  • 正如我上面评论的那样,我无法更改结构(尽管我希望我是)。如果这是唯一的解决方案,那我就不走运了……不幸的是,在我的情况下这是不可行的:(
  • 如果并且当您获得解决方案时,可能值得回馈决策,即当前结构破坏了关系数据库的几乎所有最佳实践。并且其目前和实质性的影响是使数据的分析和报告变得异常困难。
  • 决策者已经知道了 - 不幸的是,要尽快解决这个问题是不可行的。感谢您的建议!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-07
  • 1970-01-01
  • 1970-01-01
  • 2014-08-24
相关资源
最近更新 更多