什么 SQL 查询访问来自 table 两次删除的数据,完全规范化

What SQL query to access data from a table twice-removed, fully normalized

假设有三个 table,用户、订单、交易,如下所示:

Users: 
id | name
---------
1  | Mike
2  | Sara

Orders: 
id | user_id | total | transaction_id
-------------------------------------
1  |       1 |   100 |              1
2  |       2 |    10 |              2
3  |       1 |     5 |              1
4  |       1 |     4 |              3
5  |       1 |    40 |              3
6  |       2 |    80 |              2

Transactions: 
id | total |  created_at 
------------------------
1  |   105 | [timestamp]
2  |    90 | [timestamp]
3  |    44 | [timestamp]

假设我想 select users.name 但对代表最近 activity 的名称进行排序(即按最近的交易)。

如您所见,我想要的数据被删除了两次(可能误用了这个词),因为我需要查看订单 table 才能找出最近的交易。

我想我会把它设计得尽可能规范化,但后来我意识到我不知道如何为这种情况和其他类似情况构建适当的查询。我显然可以提取所有数据并在应用程序代码中进行整理。我当然也可以在我保持同步的用户上添加一个 "last_transaction_at" 列。

所以我想这个问题有两个部分。首先是如何使用 SQL 查询执行此操作,其次是这是否比反规范化效率更高或更低。

Select u.Name, MAX(created_at) TransactionTime FROM #Users u
INNER JOIN  #ORDERS o
ON u.Id = o.user_id
INNER JOIN #Transactions t
ON o.transaction_id = t.id
GROUP BY u.Name
ORDER BY MAX(created_at) desc

我觉得你创建的模式很好

标准化为更高的范式将 table 替换为组件(table 是它的投影)(关系自然)连接回原始。

为了理解 SQL 中的 join,让我们假设当我们规范化时我们将 null 视为另一个值,除了组件共享的列是 not null;没有重复的行;并且我们忽略列排序。

然后我们通过 select distinct * from 一系列 natural join 组件返回 table。或者通过每个组件的 select distinct 列名 from 一系列 inner join 组件 on 相同名称的列的相等性。

这将规范化与 joins 联系起来。但是您可能不希望完全返回分解为组件的 table 。为什么我们join?每个基数 table 包含从某些 谓词 (语句模板)通过列名参数化的 命题 (语句)的行:

-- user I is named N
User(I,N)
-- order I is user U spending $T in transaction X
Orders(I, U, T, X)
-- transaction I for $T was created on C
Transactions(I,T,C)

from 中,别名命名为 table,类似于前面的 table,但每个 column 重命名为 alias.column。它的行满足前面的谓词table。 where AND 符合其条件。

from Users u
--     user u.I is named u.N
where N = 'disantlor'
-- AND N = 'disantlor'

然后a cross join b持有满足别名谓词AND的行。并且 a inner join b 保存满足别名谓词与 on 条件的行。

from Users u
--     user u.I is named u.N
cross join Orders o
-- AND order o.I is user o.U spending $o.T in transaction o.X
inner join Transactions x on o.X = x.I
-- AND transaction x.I for $x.T was created on x.C AND  o.X = x.I
where o.U = u.I
-- AND o.U = u.I

所以我们join 得到满足给定谓词连接的行。规范化将 table 替换为谓词,使用 AND 的组件与谓词是合取的。 Is there any rule of thumb to construct SQL query from a human-readable description?

您的设计受到 select id, total from Transactions =

的约束
select transaction_id as id, sum(total) as total
from Orders
group by transaction_id

有可能您通过对某个原始 table 进行规范化而不保留 FD(功能依赖性)来获得此设计,但您所说的 "normalized" 可能只是 "well-designed"。