【问题标题】:Make a (composite) primary key for an 'item' table where the incremental 'item_id' resets per 'order_id' foreign key [duplicate]为“item”表创建一个(复合)主键,其中增量“item_id”根据“order_id”外键重置[重复]
【发布时间】:2019-06-08 22:20:59
【问题描述】:

老师希望我们讨论如何为全球业务实现收据数据库的“line_item”表。 他希望我们讨论这种“行项目”表的主键(复合键?)。如果我们的全球业务每分钟打印数千张收据(包含数百个项目),我们需要考虑多少达到 line_item_id 的 INT 上限的可能性?有没有更有效的方式来处理line_item id?

“注意:编号间隙(通常由删除引起)是可以的。同时寻找可能的竞争条件。”

考虑一下:您添加 3 张收据,每张收据 3 件。您删除了第三个收据的第二个项目。然后在第三张收据中添加一个新项目。

所以我开始想象这样的事情:(在添加/删除练习之前,收据 #1 和 #3 最初是相同的。请注意 #3 上的编号。)

|  receipt_id (FK)  |     line_id (INT)    |  line_text (TINYTEXT)  |
---------------------------------------------------------------------
|         1         |           1          |  'Apple'               |
|         1         |           2          |  'Banana'              |
|         1         |           3          |  'Coconut'             |
---------------------------------------------------------------------
|         2         |           1          |  'Apple'               |
|         2         |           2          |  'Apple'               |
|         2         |           3          |  'Apple'               |
---------------------------------------------------------------------
|         3         |           1          |  'Apple'               |
|         3         |           3          |  'Coconut'             |
|         3         |           4          |  'Dates'               |
---------------------------------------------------------------------

我们一直在学习 SQL 和 PHP(innoDB 中的 mySQLi,如果这很重要的话。) 不过我觉得这可能只用 SQL 就可以完成,对吧?

看来我应该使用第二列中的 MAX() 函数来生成 COMPOSITE PRIMARY KEY 并避免担心达到上限 INT 阈值。

我正在尝试制作一个 MySQL INSERT,它可以通过收据行的编号来做一些动态的事情,例如:

INSERT INTO line_item (3, VALUES MAX(receipt_line)+1, 'Dates')

最后他还有其他想法,例如:“如果您现在在第二张收据的末尾删除并添加一个项目怎么办?”

我想这些是他正在寻找的操作:

-- Delete the last line of the second receipt
DELETE FROM line_item WHERE receipt_id=2 AND line_id=MAX(line_id)

-- Add a new line to the second receipt.
INSERT INTO line_item VALUES ( 2, MAX(line_id)+1, 'Watermelon')

我希望得到如下结果:

|  receipt_id (FK)  |     line_id (INT)    |  line_text (TINYTEXT)  |
---------------------------------------------------------------------
|         1         |           1          |  'Apple'               |
|         1         |           2          |  'Banana'              |
|         1         |           3          |  'Coconut'             |
---------------------------------------------------------------------
|         2         |           1          |  'Apple'               |
|         2         |           2          |  'Apple'               |
|         2         |           3          |  'Watermelon'          |
---------------------------------------------------------------------
|         3         |           1          |  'Apple'               |
|         3         |           3          |  'Coconut'             |
|         3         |           4          |  'Dates'               |
---------------------------------------------------------------------

但是我得到了一堆错误和奇怪的结果。

我需要使用 PHP 来计算 line_id 吗?我错过了什么?

【问题讨论】:

标签: php mysql sql database-design


【解决方案1】:

您不能只使用MAX(line_id),因为这会在所有收据中获得最大值line_id。您想要的是一张特定收据中的最大line_id。类似SELECT MAX(line_id) FROM line_item WHERE receipt_id = 3

您可以使用子选择将其构建到单个 SQL 查询中以获取新的 line_id 值。但我认为用 PHP 会更好。首先确定新的 line_id,然后插入新的订单项。在两个单独的查询中。

还要考虑您的收据应用程序将如何删除订单项。如果我想删除收据 2 中的第二个 Apple 行项目,我需要知道它是 line_id。因此,您的应用程序需要知道它添加的新项目的line_id

【讨论】:

  • 谢谢。我现在看到了我在那里犯的错误。在阅读用户“Quassnoi”对MySQL: Add sequence column based on another field 的第三个回答后,我阅读了更多关于触发器的内容。出于几个原因,触发器似乎更可取。 1)因为它集中在 SQL 端。如果结构发生变化,这会有所帮助:只需要更新一个 SQL 触发器,而不是可能依赖它的 [可能很多] PHP 应用程序。 2) 听起来它可以解释/防止读取和写入之间可能的“竞争条件”。
  • @SaintAbsurdus 是的,这是在 PHP 端进行增量的主要缺点,您必须担心多个客户端。如果你把它放在 SQL 端,你可以使它成为一个原子操作,这样你就不会遇到这种竞争条件。但是,这带来了一个重要的问题。 PHP如何知道它刚刚添加的项目的line_id
猜你喜欢
  • 1970-01-01
  • 2016-07-04
  • 1970-01-01
  • 2017-07-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-11-30
  • 2014-07-08
相关资源
最近更新 更多