Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/249.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php 数据库设计。带3个外键的透视表还是两个透视表?_Php_Mysql_Database_Design Patterns_Database Design - Fatal编程技术网

Php 数据库设计。带3个外键的透视表还是两个透视表?

Php 数据库设计。带3个外键的透视表还是两个透视表?,php,mysql,database,design-patterns,database-design,Php,Mysql,Database,Design Patterns,Database Design,我目前正在开发一个应用程序,允许客户通过自定义表单注册活动。该自定义表单将由事件管理员为客户的特定输入生成 客户将进入表格,完成输入并选择一个地点,然后显示可用的时段。我一直坚持这两种数据库设计,不知道哪一种是更好的方法 具有3个外键的透视表 两个数据透视表 此外,我将把管理员构建的自定义表单的HTML标记存储在“form_fields”json中,让客户完成表单并将值存储在“form_data”json中。 将自定义表单和数据保存在json中是否明智 谢谢。要回答您的问题,即使有点离题: 以上

我目前正在开发一个应用程序,允许客户通过自定义表单注册活动。该自定义表单将由事件管理员为客户的特定输入生成

客户将进入表格,完成输入并选择一个地点,然后显示可用的时段。我一直坚持这两种数据库设计,不知道哪一种是更好的方法

具有3个外键的透视表 两个数据透视表 此外,我将把管理员构建的自定义表单的HTML标记存储在“form_fields”json中,让客户完成表单并将值存储在“form_data”json中。 将自定义表单和数据保存在json中是否明智


谢谢。

要回答您的问题,即使有点离题:

以上都没有

要对数据进行建模,我们必须问自己约束条件是什么。数据通常更容易定义为它不能做什么,而不是它能做什么

例如,您是否可以拥有一个Tickets记录:

没有客户记录customer\u id=null 没有时间段时间段\u id=null-时间段与活动地点或地点和时间相关。 没有事件\u id=null 如果您对所有这些问题的回答都是否定的,那么我们必须一次性将这些数据汇总在一起,但不一定在同一个表中

现在在我看来,很明显你可以/不应该有这样一张罚单:

没有分配给客户 没有事件 没有时间段 没有场地 其数量超过了您错过的活动的插槽数量 所以我假设这些是我们的基本约束条件

第二个案例的问题:

您可以在某个地点的特定时间段向客户出售门票,但不包括未知事件。记录在Tickets中,在EventCustomers表中没有记录

您还可以让客户注册参加活动,但没有门票或时间段/地点。在EventCustomers中记录,在Tickets表中没有记录

在我看来,这似乎有点不合逻辑,而且确实违反了我上面概述的限制

第一个案例的问题:

从表面上看,就我们上面的约束来看,第一种情况看起来不错。但在我工作的过程中,一些问题突然出现了。为了理解这些,作为一般规则,我们总是希望数据透视表中所有外键都有一个唯一的索引,也就是一个唯一的复合键

因此,在第一种情况下,我们希望这样:

Pivot Table 'Tickets' -
|id | customer_id | timeslot_id | event_id | form_data (json)
//for this table you would want this compound, unique index
Unique Key ticket (customer_id,timeslot_id,event_id)
这让我想到了插槽的数量,因为这意味着客户在每个活动和时间段/地点只能有一个门票记录。这与我说的你错过的部分有关,也就是说,你无法追踪你使用了多少。首先,您可能希望在此表中允许重复项。我们可以再加几张票,对吗你认为,这是一个简单的解决办法,而不是

附件A:

Pivot Table 'Tickets' -
|id | customer_id | timeslot_id | event_id | form_data (json)
| 1 |      1      |      1      |     1    | {}
| 2 |      1      |      1      |     1    | {}

同时考虑了一些基本的DB设计规则:

在一个好的数据库设计中,您总是希望

代理主键,与数据无关的键,这是id 一个自然密钥,一个作为数据一部分的唯一密钥。例如,如果您有一个吸引客户的电子邮件字段,您可以将其设置为唯一的,以防止添加重复的客户。它是一段数据,本质上是唯一的,是数据的一部分。 第一个代理键允许您在不了解数据本身的情况下使用数据。这很好,因为它给了我们一些关注点的分离,代码和数据之间的一些抽象。当您在主键、外键关系上连接两个表时,您不需要了解有关数据的任何其他信息

第二个自然密钥对于防止重复数据至关重要。对于透视表,外键(它们各自表中的代理键)将成为透视表中的自然键。现在,它们是透视表上下文中数据的一部分,它们唯一且自然地标识该数据

为什么独特性如此重要

一旦您允许数据透视表重复,您将遇到几个问题,尤其是如果您有表单_数据之类的附件数据:

如何区分这些记录? 哪一份副本是权威副本,由谁负责。 如果您需要更改表单数据,您如何同步该附件数据,您将在哪个记录中更改它。只有一个?哪一个?二者都如何保持所有副本的同步。 如果输入了一个意外的副本,你怎么知道它是意外的呢?你怎么知道这是一个真正的重复或真正的重复,而不是一个有效的记录。 即使你知道这是一个偶然的重复,你如何决定哪一个重复应该被删除,这可以追溯到哪个是权威记录。 很快,它就变成了一个m 需要处理的问题

最后,我的建议是什么

Table 'customer' - 
| id | name |

Table 'event' -
| id | name | form_fields (json)

Table 'venue' -
| id |  address | slots |

Table 'show' -
| id | datetime | venue_id | event_id | 

Table 'purchase' -
| id | show_id | customer_id | slots | created |

Table 'ticket' ( customers_shows )
| id | purchase_id | guid |
我更改了很多内容,您可以使用部分或全部这些更改:

我把复数名改为单数。我只在使用没有辅助数据的透视表时才使用复数,这样的名称就是VICENTIONS\U事件。这是因为来自客户的记录是单个实体,我不需要进行任何连接来获取有用的数据。来自我们假设的场馆\ U活动的记录将包含2个实体,因此我会立即知道,无论发生什么情况,我都需要加入,因为除了外键之外,没有其他数据

现在在show的例子中,您可能会注意到它本质上是一个透视表。那么,为什么我不把它命名为我上面列出的场馆和活动呢。原因是我们有一个datetime列,这就是我所说的附件数据。所以在这种情况下,如果我只需要datetime,而不需要连接,我就可以从show中提取数据。因此,可以将其视为具有多对一关系的单个实体。多对多是多对一和一对多,这就是为什么我们以后需要更多的数据透视表

字母大小写和间距。我建议使用所有小写字母,不使用空格。MySql区分大小写,不能很好地使用空格。从一个不需要记住的角度来看,它更容易,我们是把它命名为venuesEvents还是venuesEvents或venuesEvents等等。。。在良好的数据库设计中,命名约定的一致性是至关重要的

以上主要是基于观点的,这是我的答案,所以这是我的观点。处理它

桌上表演 我把slotscolumn移到了场地。我假设场地将决定有多少个可用的位置,我认为这是场地本身的物理要求或属性。例如,一家电影院只有X个座位,无论电影在什么时候放映,都不会改变有多少座位。如果这些假设是正确的,那么每次我们进入一场演出时,记住一个场馆有多少座位就可以省下很多工作

我更改时间段的原因是,在两种原始情况下,数据模型中都存在一些不协调。有些东西不能像它们应该的那样紧密地联系在一起。例如,您的时间段与事件没有直接关系

附件B使用您的结构:

Table 'event' -
| id |    name   | form_fields (json) |
| 1  | "Event A" | "{}"               |
| 2  | "Event B" | "{}"               |

 Table 'Venues' -
| id |    address   | event_id |
|  1 | "123 ABC SE" |    1     |
|  2 | "123 AB SE"  |    2     | //address entered wrong as AB instead ABC

Table 'Timeslots' -
| id |        datetime       | slots | venue_id |
| 1  | "2018-01-27 04:41:23" | 200   |    1     |
| 2  | "2018-01-27 04:41:23" | 200   |    2     |
在上面的展品中,我们可以看到,我们必须立即复制地址,以便在给定地点创建多个活动。因此,如果地址输入错误,在某些场所可能是正确的,而在其他场所可能是错误的。这可能是一个真正的问题,因为从编程角度来说,当此记录的场馆ID和活动ID都不同时,您如何知道AB应该是ABC。基本上,在运行时如何区分这些记录?你会发现这很难做到。主要的问题是Veneues中有太多的数据,你试图用它做太多的事情,这种关系不符合数据的约束

这还不是最糟糕的,因为还有一个问题,因为现在场地id不同了,我们可以破坏我们的时隙表,在同一地点同时有两条记录。然后,因为插槽被绑定到这个表上,我们也可以破坏下游的东西,比如在那个时间和地点卖出更多的票。一切都开始破裂

即使计算某一特定地点的演出数量成为一个真正的挑战,这个缺陷也存在于您提供的两个数据模型中

我的模型中的数据相同

#with Unique compound Key datetime_venue_id( show.datetime, show.venue_id)

 Table 'event' -
 | id |    name   | form_fields (json) |
 | 1  | "Event A" | "{}"               |
#| 2  | "Event B" | "{}"               |

 Table 'venue' -
 | id |   address    |  slots    |
 |  1 | "123 ABC SE" |    200    |

 Table 'show' -
 | id | datetime              | venue_id | event_id | 
 | 1  | "2018-01-27 04:41:23" |   1      |    1     |
#| 2  | "2018-01-27 04:41:23" |   1      |    2     | 
如您所见,您不再有重复的地址。虽然看起来你可以在同一时间为同一地点参加2场演出,但这只是因为我们没有包含日期时间和地点id的复合唯一键a.k.a.唯一键datetime\U venue\U id datetime,venue\U id。如果你试图插入具有该约束的数据,MySql会对你造成影响。如果在同一个事务中同时包含inserts event和show,我会这样做,在innodb引擎中,整个过程都会失败并回滚,事件或show都不会被插入

现在,你可以试着争辩说,你可能对附件B有相同的唯一约束,但由于那里的场馆ID不同,你就错了

无论如何,show是我们新的主数据透视表,带有来自event和vention的外键,然后是附件数据datetime

除了上面提到的内容外,与旧结构相比,此设置还提供了一些优势,在这张表中,我们现在可以访问:

参加桌上活动的活动是什么?在哪里 事件时间戳是什么时候 参加桌上活动可获得多少活动时段 这一切都围绕着表演记录。我们可以建立一个独立于客户或门票的表演。因为事实上,客户并不是展会的一部分,而将他们包括在展会中的时间长短取决于您在数据模型中对它的看法,这一切都会让我感到困惑 我要挂断电话

附件C

#in your first case
Pivot Table 'Tickets' -
|id | customer_id | timeslot_id | event_id | form_data (json)

#in your second case
Pivot Table 'Tickets' -
| id | customer_id | timeslot_id |

Pivot Table 'EventCustomers' -
| id | customer id | event_id | form_data (json)
正如我上面所说的,如果在两个数据模型中都没有客户ID,您就不能将我所说的“显示什么”、“在哪里”和“何时”放在一起。当您稍后围绕此构建应用程序时,它将成为一个巨大的问题。这在运行时可能是无法克服的。基本上,您需要收集所有数据并等待客户id。在您的两种型号中,情况并非如此,而且您可能无法轻松访问某些数据。例如,对于旧结构的第一种情况,您如何知道时隙_id=20和事件_id=32加上一个客户等于一张有效票据?时间段和包含客户的透视表之外的事件之间没有直接关系。timeslot_id=20可能对任何事件都有效,您无法知道这一点

它是如此容易抓取说显示=32,并检查有多少插槽剩余,然后只做购买记录。一切都准备好了,等待着它

表格购买 我还添加了购买表或订单表,即使节目是免费的,该表也为我们提供了一些非常有用的工具。这也是一个透视表,但它有一些附件数据,就像show一样。插槽和已创建

这张桌子

我们在这里将customer表绑定到show表 我们有一个“已创建”字段,这样您就可以知道此记录是何时创建的,何时购买了票证 我们也有一些客户将使用的插槽,我们可以在show_id上对插槽进行汇总,以查看我们已经售出了多少插槽。通过从一个节目到另一个场馆的一次连接,我们可以找出这个节目总共有多少个插槽,这些插槽使用了我们上面使用的相同的整数key show.id来聚合。那么比较这两个问题就很简单了,如果你想变得有趣,你可以在一个查询中完成这一切。 餐桌票 现在你可能需要也可能不需要这张桌子。它与表购买有多对一关系。所以一个订单可以有很多票。这里的记录将在购买时生成,数量取决于插槽中的内容。此表的主要用途只是为每个票据提供唯一的记录。为此,我有一个guid列,它可以是唯一的散列。基本上,这将给你一些跟踪个人票的能力,我真的没有足够的信息知道这将如何在你的情况下工作。如果不需要搜索该表,您甚至可以用JSON数据替换该表,这将使在某些票被退款的情况下更容易维护该表。但正如我所暗示的,这取决于您的特定用例

一些简单的SQL示例

加入所有内容只是为了显示关系:

SELECT
    {some fields}
FROM
    ticket AS t
JOIN
    puchase AS p ON t.purchase_id = p.id
JOIN    
    customer AS c ON p.customer_id = c.id
JOIN
    show AS s ON p.show_id = s.id
JOIN
    venue AS v ON s.venue_id = s.id
JOIN
    event AS e ON s.event_id = e.id    
计算用于演出的已用时段:

SELECT
    SUM(slots) AS used_slots
FROM
    puchase
WHERE
    show_id = :show_id
GROUP BY show_id
SELECT
    v.name,
    v.slots
FROM
    venue AS v
JOIN
    show AS s ON s.venue_id = v.id
WHERE
    v.show_id = :show_id
    # or you could do s.id = :show_id
获取节目的可用插槽:

SELECT
    SUM(slots) AS used_slots
FROM
    puchase
WHERE
    show_id = :show_id
GROUP BY show_id
SELECT
    v.name,
    v.slots
FROM
    venue AS v
JOIN
    show AS s ON s.venue_id = v.id
WHERE
    v.show_id = :show_id
    # or you could do s.id = :show_id
所有表都以不同的字母开头,这也很好,这使得别名更容易

-注意-table name事件可能是MySql中的一个保留字,我不确定它是否可以用作表名。根据查询使用的上下文,某些保留字在查询的某些部分仍然有效。即使这是真的,我相信你能想出一个解决办法。巧合的是,这就是为什么我将“购买”命名为“订单”,而不是“订单”,因为“订单”是一个保留字。我只是碰巧想到了这件事


我希望这有帮助,也有意义。我可能在这方面花的时间比我应该花的要多,但我设计这样的东西是为了谋生,我真的很喜欢其中的数据架构部分,所以我有时会有点忘乎所以。

要回答你的问题,即使它有点离题:

以上都没有

要对数据进行建模,我们必须问自己约束条件是什么。数据通常更容易定义为它不能做什么,而不是它能做什么

例如,您是否可以拥有一个Tickets记录:

没有客户记录customer\u id=null 没有时间段时间段\u id=null-时间段与活动地点或地点和时间相关。 没有事件\u id=null 如果您对所有这些问题的回答都是否定的,那么我们必须一次性将这些数据汇总在一起,但不一定在同一个表中

现在在我看来,很明显你可以/不应该有这样一张罚单:

没有分配给客户 没有事件 没有时间段 没有场地 其数量超过了您错过的活动的插槽数量 所以我假设这些是我们的基本约束条件

第二个案例的问题:

您可以在某个地点的特定时间段向客户出售门票,但不包括未知事件。记录在Tickets中,在EventCustomers表中没有记录

您还可以让客户注册参加活动,但没有门票或时间段/地点。在EventCustomers中记录,在Tickets表中没有记录

在我看来,这似乎有点不合逻辑,事实上,这违反了规定 我上面概述的火车

第一个案例的问题:

从表面上看,就我们上面的约束来看,第一种情况看起来不错。但在我工作的过程中,一些问题突然出现了。为了理解这些,作为一般规则,我们总是希望数据透视表中所有外键都有一个唯一的索引,也就是一个唯一的复合键

因此,在第一种情况下,我们希望这样:

Pivot Table 'Tickets' -
|id | customer_id | timeslot_id | event_id | form_data (json)
//for this table you would want this compound, unique index
Unique Key ticket (customer_id,timeslot_id,event_id)
这让我想到了插槽的数量,因为这意味着客户在每个活动和时间段/地点只能有一个门票记录。这与我说的你错过的部分有关,也就是说,你无法追踪你使用了多少。首先,您可能希望在此表中允许重复项。我们可以再加几张票,对吗你认为,这是一个简单的解决办法,而不是

附件A:

Pivot Table 'Tickets' -
|id | customer_id | timeslot_id | event_id | form_data (json)
| 1 |      1      |      1      |     1    | {}
| 2 |      1      |      1      |     1    | {}

同时考虑了一些基本的DB设计规则:

在一个好的数据库设计中,您总是希望

代理主键,与数据无关的键,这是id 一个自然密钥,一个作为数据一部分的唯一密钥。例如,如果您有一个吸引客户的电子邮件字段,您可以将其设置为唯一的,以防止添加重复的客户。它是一段数据,本质上是唯一的,是数据的一部分。 第一个代理键允许您在不了解数据本身的情况下使用数据。这很好,因为它给了我们一些关注点的分离,代码和数据之间的一些抽象。当您在主键、外键关系上连接两个表时,您不需要了解有关数据的任何其他信息

第二个自然密钥对于防止重复数据至关重要。对于透视表,外键(它们各自表中的代理键)将成为透视表中的自然键。现在,它们是透视表上下文中数据的一部分,它们唯一且自然地标识该数据

为什么独特性如此重要

一旦您允许数据透视表重复,您将遇到几个问题,尤其是如果您有表单_数据之类的附件数据:

如何区分这些记录? 哪一份副本是权威副本,由谁负责。 如果您需要更改表单数据,您如何同步该附件数据,您将在哪个记录中更改它。只有一个?哪一个?二者都如何保持所有副本的同步。 如果输入了一个意外的副本,你怎么知道它是意外的呢?你怎么知道这是一个真正的重复或真正的重复,而不是一个有效的记录。 即使你知道这是一个偶然的重复,你如何决定哪一个重复应该被删除,这可以追溯到哪个是权威记录。 在短期内,它真的成为一个混乱的处理

最后,我的建议是什么

Table 'customer' - 
| id | name |

Table 'event' -
| id | name | form_fields (json)

Table 'venue' -
| id |  address | slots |

Table 'show' -
| id | datetime | venue_id | event_id | 

Table 'purchase' -
| id | show_id | customer_id | slots | created |

Table 'ticket' ( customers_shows )
| id | purchase_id | guid |
我更改了很多内容,您可以使用部分或全部这些更改:

我把复数名改为单数。我只在使用没有辅助数据的透视表时才使用复数,这样的名称就是VICENTIONS\U事件。这是因为来自客户的记录是单个实体,我不需要进行任何连接来获取有用的数据。来自我们假设的场馆\ U活动的记录将包含2个实体,因此我会立即知道,无论发生什么情况,我都需要加入,因为除了外键之外,没有其他数据

现在在show的例子中,您可能会注意到它本质上是一个透视表。那么,为什么我不把它命名为我上面列出的场馆和活动呢。原因是我们有一个datetime列,这就是我所说的附件数据。所以在这种情况下,如果我只需要datetime,而不需要连接,我就可以从show中提取数据。因此,可以将其视为具有多对一关系的单个实体。多对多是多对一和一对多,这就是为什么我们以后需要更多的数据透视表

字母大小写和间距。我建议使用所有小写字母,不使用空格。MySql区分大小写,不能很好地使用空格。从一个不需要记住的角度来看,它更容易,我们是把它命名为venuesEvents还是venuesEvents或venuesEvents等等。。。在良好的数据库设计中,命名约定的一致性是至关重要的

以上主要是基于观点的,这是我的答案,所以这是我的观点。处理它

桌上表演 我把slotscolumn移到了场地。我假设场地将决定有多少个可用的位置,我认为这是场地本身的物理要求或属性。例如,一家电影院只有X个座位,无论电影在什么时候放映,都不会改变有多少座位。如果这些假设是正确的,那么每次我们进入一场演出时,记住一个场馆有多少座位就可以省下很多工作

我更改时间段的原因是,在两种原始情况下,数据模型中都存在一些不协调。有些东西根本就不能联系在一起 这是他们应该做的。例如,您的时间段与事件没有直接关系

附件B使用您的结构:

Table 'event' -
| id |    name   | form_fields (json) |
| 1  | "Event A" | "{}"               |
| 2  | "Event B" | "{}"               |

 Table 'Venues' -
| id |    address   | event_id |
|  1 | "123 ABC SE" |    1     |
|  2 | "123 AB SE"  |    2     | //address entered wrong as AB instead ABC

Table 'Timeslots' -
| id |        datetime       | slots | venue_id |
| 1  | "2018-01-27 04:41:23" | 200   |    1     |
| 2  | "2018-01-27 04:41:23" | 200   |    2     |
在上面的展品中,我们可以看到,我们必须立即复制地址,以便在给定地点创建多个活动。因此,如果地址输入错误,在某些场所可能是正确的,而在其他场所可能是错误的。这可能是一个真正的问题,因为从编程角度来说,当此记录的场馆ID和活动ID都不同时,您如何知道AB应该是ABC。基本上,在运行时如何区分这些记录?你会发现这很难做到。主要的问题是Veneues中有太多的数据,你试图用它做太多的事情,这种关系不符合数据的约束

这还不是最糟糕的,因为还有一个问题,因为现在场地id不同了,我们可以破坏我们的时隙表,在同一地点同时有两条记录。然后,因为插槽被绑定到这个表上,我们也可以破坏下游的东西,比如在那个时间和地点卖出更多的票。一切都开始破裂

即使计算某一特定地点的演出数量成为一个真正的挑战,这个缺陷也存在于您提供的两个数据模型中

我的模型中的数据相同

#with Unique compound Key datetime_venue_id( show.datetime, show.venue_id)

 Table 'event' -
 | id |    name   | form_fields (json) |
 | 1  | "Event A" | "{}"               |
#| 2  | "Event B" | "{}"               |

 Table 'venue' -
 | id |   address    |  slots    |
 |  1 | "123 ABC SE" |    200    |

 Table 'show' -
 | id | datetime              | venue_id | event_id | 
 | 1  | "2018-01-27 04:41:23" |   1      |    1     |
#| 2  | "2018-01-27 04:41:23" |   1      |    2     | 
如您所见,您不再有重复的地址。虽然看起来你可以在同一时间为同一地点参加2场演出,但这只是因为我们没有包含日期时间和地点id的复合唯一键a.k.a.唯一键datetime\U venue\U id datetime,venue\U id。如果你试图插入具有该约束的数据,MySql会对你造成影响。如果在同一个事务中同时包含inserts event和show,我会这样做,在innodb引擎中,整个过程都会失败并回滚,事件或show都不会被插入

现在,你可以试着争辩说,你可能对附件B有相同的唯一约束,但由于那里的场馆ID不同,你就错了

无论如何,show是我们新的主数据透视表,带有来自event和vention的外键,然后是附件数据datetime

除了上面提到的内容外,与旧结构相比,此设置还提供了一些优势,在这张表中,我们现在可以访问:

参加桌上活动的活动是什么?在哪里 事件时间戳是什么时候 参加桌上活动可获得多少活动时段 这一切都围绕着表演记录。我们可以建立一个独立于客户或门票的表演。因为事实上,客户并不是展会的一部分,根据您在数据模型中的看法,将他们包括在展会中的时间长短,会使一切变得混乱

附件C

#in your first case
Pivot Table 'Tickets' -
|id | customer_id | timeslot_id | event_id | form_data (json)

#in your second case
Pivot Table 'Tickets' -
| id | customer_id | timeslot_id |

Pivot Table 'EventCustomers' -
| id | customer id | event_id | form_data (json)
正如我上面所说的,如果在两个数据模型中都没有客户ID,您就不能将我所说的“显示什么”、“在哪里”和“何时”放在一起。当您稍后围绕此构建应用程序时,它将成为一个巨大的问题。这在运行时可能是无法克服的。基本上,您需要收集所有数据并等待客户id。在您的两种型号中,情况并非如此,而且您可能无法轻松访问某些数据。例如,对于旧结构的第一种情况,您如何知道时隙_id=20和事件_id=32加上一个客户等于一张有效票据?时间段和包含客户的透视表之外的事件之间没有直接关系。timeslot_id=20可能对任何事件都有效,您无法知道这一点

它是如此容易抓取说显示=32,并检查有多少插槽剩余,然后只做购买记录。一切都准备好了,等待着它

表格购买 我还添加了购买表或订单表,即使节目是免费的,该表也为我们提供了一些非常有用的工具。这也是一个透视表,但它有一些附件数据,就像show一样。插槽和已创建

这张桌子

我们在这里将customer表绑定到show表 我们有一个“已创建”字段,这样您就可以知道此记录是何时创建的,何时购买了票证 我们也有一些客户将使用的插槽,我们可以在show_id上对插槽进行汇总,以查看我们已经售出了多少插槽。通过从一个节目到另一个场馆的一次连接,我们可以找出这个节目总共有多少个插槽,这些插槽使用了我们上面使用的相同的整数key show.id来聚合。那么比较这两个问题就很简单了,如果你想变得有趣,你可以在一个查询中完成这一切。 餐桌票 现在你可能需要也可能不需要这张桌子。它与表购买有多对一关系。所以一个订单可以有很多票。这里的记录将在购买时生成,数量取决于插槽中的内容。此表的主要用途只是为每个票据提供唯一的记录。为此,我有一个guid列 可以是唯一的散列。基本上,这将给你一些跟踪个人票的能力,我真的没有足够的信息知道这将如何在你的情况下工作。如果不需要搜索该表,您甚至可以用JSON数据替换该表,这将使在某些票被退款的情况下更容易维护该表。但正如我所暗示的,这取决于您的特定用例

一些简单的SQL示例

加入所有内容只是为了显示关系:

SELECT
    {some fields}
FROM
    ticket AS t
JOIN
    puchase AS p ON t.purchase_id = p.id
JOIN    
    customer AS c ON p.customer_id = c.id
JOIN
    show AS s ON p.show_id = s.id
JOIN
    venue AS v ON s.venue_id = s.id
JOIN
    event AS e ON s.event_id = e.id    
计算用于演出的已用时段:

SELECT
    SUM(slots) AS used_slots
FROM
    puchase
WHERE
    show_id = :show_id
GROUP BY show_id
SELECT
    v.name,
    v.slots
FROM
    venue AS v
JOIN
    show AS s ON s.venue_id = v.id
WHERE
    v.show_id = :show_id
    # or you could do s.id = :show_id
获取节目的可用插槽:

SELECT
    SUM(slots) AS used_slots
FROM
    puchase
WHERE
    show_id = :show_id
GROUP BY show_id
SELECT
    v.name,
    v.slots
FROM
    venue AS v
JOIN
    show AS s ON s.venue_id = v.id
WHERE
    v.show_id = :show_id
    # or you could do s.id = :show_id
所有表都以不同的字母开头,这也很好,这使得别名更容易

-注意-table name事件可能是MySql中的一个保留字,我不确定它是否可以用作表名。根据查询使用的上下文,某些保留字在查询的某些部分仍然有效。即使这是真的,我相信你能想出一个解决办法。巧合的是,这就是为什么我将“购买”命名为“订单”,而不是“订单”,因为“订单”是一个保留字。我只是碰巧想到了这件事


我希望这有帮助,也有意义。我可能在这方面花的时间比我应该花的要多,但我设计这样的东西是为了谋生,我真的很喜欢其中的数据架构部分,所以我有时会有点忘乎所以。

你的模型有什么限制,这是你必须问的问题。你能卖一张没有活动的票吗?可能不会。你能有一个不举办活动的场地吗。这应该决定关系。一个场馆可以有许多活动,一个活动可以在许多场馆举行。让数据的需求决定模型。你可以想,哦,连接这个表和那个表会很好。但它符合要求吗?如果不了解全部数据,很难回答这个问题。有时,这是一个我们必须经过的过程来解决它。你的模型有什么约束,这是你必须问的问题。你能卖一张没有活动的票吗?可能不会。你能有一个不举办活动的场地吗。这应该决定关系。一个场馆可以有许多活动,一个活动可以在许多场馆举行。让数据的需求决定模型。你可以想,哦,连接这个表和那个表会很好。但它符合要求吗?如果不了解全部数据,很难回答这个问题。有时,这是一个我们必须经历的过程来解决它。