【发布时间】:2010-11-02 12:57:42
【问题描述】:
假设我有一张客户表:
CREATE TABLE customers (
customer_number INTEGER,
customer_name VARCHAR(...),
customer_address VARCHAR(...)
)
此表没有有主键。但是,customer_name 和 customer_address 应该对于任何给定的 customer_number 都是唯一的。
此表包含许多重复客户的情况并不少见。为了避免这种重复,以下查询仅用于隔离唯一客户:
SELECT
DISTINCT customer_number, customer_name, customer_address
FROM customers
幸运的是,该表格历来包含准确的数据。也就是说,对于任何customer_number,从来没有冲突的customer_name 或customer_address。但是,假设有冲突的数据确实进入了表中。我希望编写一个会失败的查询,而不是为有问题的customer_number 返回多行。
例如,我尝试了这个查询没有成功:
SELECT
customer_number, DISTINCT(customer_name, customer_address)
FROM customers
GROUP BY customer_number
有没有办法使用标准 SQL 编写这样的查询?如果没有,在 Oracle 特定的 SQL 中是否有解决方案?
编辑:奇怪查询背后的基本原理:
说实话,这个客户表实际上并不存在(谢天谢地)。我创建了它,希望它足够清晰来展示查询的需求。但是,基于该示例,人们(幸运地)意识到对此类查询的需求是我最不担心的。因此,我现在必须剥离一些抽象概念,并希望恢复我提出这种可憎的桌子的声誉......
我从外部系统收到一个包含发票(每行一个)的平面文件。我逐行读取此文件,将其字段插入此表:
CREATE TABLE unprocessed_invoices (
invoice_number INTEGER,
invoice_date DATE,
...
// other invoice columns
...
customer_number INTEGER,
customer_name VARCHAR(...),
customer_address VARCHAR(...)
)
如您所见,来自外部系统的数据是非规范化的。也就是说,外部系统在同一行上同时包含发票数据及其关联的客户数据。多张发票可能会共享同一个客户,因此可能会有重复的客户数据。
在保证所有客户都已在系统中注册之前,系统无法开始处理发票。因此,系统必须识别唯一客户并在必要时对其进行注册。这就是我想要查询的原因:因为我正在处理我无法控制的非规范化数据。
SELECT
customer_number, DISTINCT(customer_name, customer_address)
FROM unprocessed_invoices
GROUP BY customer_number
希望这有助于澄清问题的初衷。
编辑:好/坏数据示例
澄清一下:customer_name 和 customer_address 只需对于特定的 customer_number 是唯一的。
customer_number | customer_name | customer_address
----------------------------------------------------
1 | 'Bob' | '123 Street'
1 | 'Bob' | '123 Street'
2 | 'Bob' | '123 Street'
2 | 'Bob' | '123 Street'
3 | 'Fred' | '456 Avenue'
3 | 'Fred' | '789 Crescent'
前两行没问题,因为customer_number 1 的customer_name 和customer_address 相同。
中间两行没问题,因为customer_number 2 的customer_name 和customer_address 相同(即使另一个customer_number 具有相同的customer_name 和customer_address)。
最后两行不行,因为customer_number 3 有两个不同的customer_addresses。
如果针对所有六行运行,我正在查找的查询将失败。但是,如果实际只存在前四行,则视图应该返回:
customer_number | customer_name | customer_address
----------------------------------------------------
1 | 'Bob' | '123 Street'
2 | 'Bob' | '123 Street'
我希望这能澄清我所说的“customer_name 和 customer_address 冲突”的意思。根据customer_number,它们必须是唯一的。
感谢那些解释如何从外部系统正确导入数据的人。事实上,我已经在做大部分工作了。我故意隐藏了我正在做的所有细节,以便更容易专注于手头的问题。此查询并不是唯一的验证形式。我只是认为这会是一个很好的画龙点睛(可以说是最后的防守)。这个问题只是为了调查 SQL 的可能性。 :)
【问题讨论】:
-
“失败,而不是返回多行”是什么意思?通常当我想到一个 sql 查询失败时,这意味着我没有行,或者我正在加入的表的产品。我虽然您正在寻找 select * from (select count(*) as cnt, customer_number, customer_name, customer_address From customers group by customer_number, customer_name, customer_address) where cnt > 1 type of query.
-
“失败”是指 DBMS 应该返回错误而不是结果(例如当您查询不存在的表时)。我知道我可以使用“SELECT COUNT(*) ... GROUP BY ... HAVING ...”查询来识别冲突数据的存在,但是我只是想看看是否有类似于我的查询描述的确实存在。谢谢你的评论,不过! :)
标签: sql denormalization