【问题标题】:What SQL query to access data from a table twice-removed, fully normalized从表中访问数据的 SQL 查询两次删除,完全规范化
【发布时间】:2018-01-20 05:09:30
【问题描述】:

假设有三个表,用户、订单、交易,看起来像这样:

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]

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

正如您所见,我需要的数据被删除了两次(可能是误用了这个词),因为我需要通过订单表找出最近的交易。

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

所以我想这个问题有两个部分。首先是如何使用 SQL 查询来做到这一点,其次是这是否比反规范化效率更高或更低。

【问题讨论】:

  • 如果两个用户有相同的名字,你到底想要什么?按具有该名称的某些用户的最近交易顺序列出的名称?还是一个列表,其中第 n 个元素是具有最近第 n 个交易时间的用户的名称?

标签: mysql sql database-design normalization database-normalization


【解决方案1】:

归一化到更高的范式用组件(作为它的投影的表)替换表格,这些组件(关系自然)连接回原始表格。

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

然后我们通过select distinct * from 取回表格的natural joins 组件序列。或者通过每个组件的select distinct 列名 from 一系列inner joins 的组件on 同名列的相等性。

这将规范化与joins 联系起来。但是您可能不想准确地返回您分解为组件的表。为什么我们join?每个基表都包含根据列名参数化的某些谓词(语句模板)构成真正命题(语句)的行:

-- 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 中,别名将表命名为与前面的表类似,但每个column 都重命名为alias.column。它的行满足上表的谓词。 where 与它的条件。

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 包含满足别名谓词的 AND 和 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 来获取满足给定谓词连接的行。并且规范化使用带有谓词的组件使用 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

您可能通过规范化某个原始表而不保留 FD(功能依赖关系)来获得此设计,但您所说的“规范化”可能只是“精心设计”。 Cross Table Dependency/Constraint in SQL Database

【讨论】:

    【解决方案2】:
    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
    

    我觉得你创建的架构很好

    【讨论】:

      猜你喜欢
      • 2013-11-17
      • 2014-10-21
      • 2010-11-02
      • 2017-05-09
      • 1970-01-01
      • 2013-03-08
      • 2015-09-23
      • 2020-08-14
      • 2023-03-03
      相关资源
      最近更新 更多