【问题标题】:MySQL large relational queryMySQL 大型关系查询
【发布时间】:2013-10-04 13:53:31
【问题描述】:

我有几张桌子:

letter_mail

index   
sent    
from    
to  
template    
public  
stamp   
stationery  
title   
content     
opened 

letter_user

index   
username    
password 

letter_mail 中的所有行都是与另一个表相关的,除了 index、public 和 opens。

letter_mail 中的 From 和 To 对应于 letter_user 的索引。我想要的是从数据库中提取所有数据,如果可能的话,最好在一个查询中。 A * 在 letter_mail 行上选择会产生类似这样的结果:

index:1     
sent: 2013-10-03    
from:1  
to:2    
template:1  
public:1    
stamp:1     
stationery:1    
title: 1    
content: 1  
opened : 0

我需要的是,上面的信息用相关表中的数据填充并进行JSON 编码。看起来有点像这样:

index:1     
sent: 2013-10-03    
from: {1, John}     
to: {2, Jane}   
template: {index: 1, template: "standard template", url: "template_name"}   
public: 0       
stamp: {index: 1, stamp: "standard stamp", url: "some/url"}     
stationery: {index: 1, stamp: "standard stationery", url: "some/url"}       
title: {index: 1, title: "some title"}      
content: {index: 1, content: "some text content"}       
opened : 0

这完全疯了吗?我应该将查询分成几位还是将所有内容一起整理到一个表中?

如果您需要更多信息,请告知:)

解决办法是这样的

select 
  mail.index,
  mail.sent,
  mail.opened,
  mail.public, 
  FromU.username as FromUser, 
  ToU.username as ToUser, 
  T.template as TemplateName, 
  T.url as TemplateURL, 
  S.stamp, 
  S.url as StampURL, 
  S.stamp Stamp, 
  STA.url StationaryURL, 
  Ttl.title, 
  C.content
from 
  letter_mail mail
     JOIN letter_user FromU
        on mail.from = FromU.index 
     JOIN letter_user ToU
        on mail.to = ToU.index 
     JOIN letter_templates T
        on mail.template = T.index
     JOIN letter_stamps S
        on mail.stamp = S.index
     JOIN letter_stationery STA
        on mail.stationery = STA.index 
     JOIN letter_title Ttl
        on mail.title = Ttl.index 
     JOIN letter_content C
        on mail.content = C.index

查询有效,但不返回任何行。

【问题讨论】:

  • 并不疯狂——尽管您最终会得到大量重复数据,在一次查询中一次获得所有数据。这是否是一个好主意取决于数据的数量以及从网络服务器到数据库的接近度/连接。
  • 我只是想避免有 9 个选择查询,但如果这是它所需要的,那么......是的。我可以将查询中的所有数据存储在主表中,但这也会在查询一件事时产生开销。另外,如果人们不赞成,请说明原因:)
  • 不是我 - 有些人只是记下他们认为基本的任何问题。除非应该,否则不要将所有数据放在一个表中,以避免数据重复,这是关系数据库的主要点。您应该只需要两个查询,尽管每个表一个。链接可以在 PHP 中完成。

标签: php mysql sql json


【解决方案1】:

正如 dmcnelis 所指出的,您可以考虑使用连接(比旧的 ANSI 格式的表格列表和应用 WHERE 标准更现代的语法)。这是他使用 JOIN 语法的版本。我还更改为在表上使用较短的别名引用。请注意,JOIN/ON 准确地显示了 tableX 与 tableY 的关系,而不是隐藏在 WHERE 子句中。如果 OOps 忘记了 where 子句,这有时会导致问题和笛卡尔结果。通过 JOIN,您将立即看到您的关系标准。

select 
      L.sent, 
      FromU.username as FromUser, 
      ToU.username as ToUser, 
      T.name as TemplateName, 
      T.url as TemplateURL, 
      L.public, 
      S.stamp, 
      S.url as StampURL, 
      STA.stamp StationaryStamp, 
      STA.url StationaryURL, 
      title.title, 
      C.content, 
      L.opened
   from 
      letter_mail L
         JOIN letter_user FromU
            on L.from = FromU.index 
         JOIN letter_user ToU
            on L.to = ToU.index 
         JOIN template T
            on L.Template = T.index
         JOIN stamp S
            on L.Stamp = S.index
         JOIN stationary STA
            on L.Stationary = STA.index 
         JOIN title
            on L.title = title.index 
         JOIN content C
            on L.Content = C.index

现在所有的表都是相关的,运行查询,它会得到你需要的一切。但是,如果您正在寻找符合特定条件的东西,只需添加一个 WHERE 子句...例如

WHERE
      L.From = 27
   OR L.To = 27

接收来自用户 27 的任何电子邮件。

如果您只想要特定的文具、印章、标题等,只需根据需要添加即可。

【讨论】:

  • 这有意义吗?还是我应该重组数据库?
  • 我认为您如何将事情分解并没有错...在数据库中拥有许多查找表是很常见的。想想如果您有 100,000 条记录并且必须重复固定类型“标准固定”与内部 ID 8。然后您拼写错误?修复查找表,您就完成了。您的上下文看起来不错。
  • 有效!谢谢!我已经用您的答案更新了问题,并通过投票奖励了任何导致此答案的人。
  • @Eirinn,更大的元素...您现在看到 JOINS 与 FROM/WHERE 组合的相关性了吗,如 dmcnelis 所示,两者都是有效的,但是 JOINS 在实践中更常见查询。
  • 嗯是为了防止多次扫描一张表?
【解决方案2】:

简而言之,您可以使用表别名多次连接同一个表。我对其他相关的表名做了一些假设,但基本上你最终会得到一个看起来像这样的查询:

select 
    sent, from.username, to.username, template_table.name, template_table.url, public, 
    stamp_table.stamp, stamp_table.url, stationary_table.stamp, stationary_table.url, title_table.title, 
    content_table.content, opened
from 
    letter_mail l, 
    letter_user from, 
    letter_user to, 
    template template_table, 
    stamp stamp_table, 
    stationairy stationary_table, 
    title title_table, 
    content content_table
where 
    l.from = from.idex
    and l.to = to.index
    and template = template_table.index
    and stamp = stamp_table.index
    and stationairy = stationary_table.index
    and title = title_table.index
    and content = content_table.index
    where l.index = X

您将遇到的主要问题是,这将导致对 letter_user 表进行多次扫描......这可能是可以避免的,但如果该数据库具有任何真正的显着大小,您应该记住这一点。

与整理多个数据库调用相比,像这样进行查询的好处是,您让数据库完成其设计的工作,并且只对数据库进行一次调用。

当然,这个查询可以稍微修改一下,以专门使用连接......但对我来说,这种形式更易于阅读和理解,假设您只需要严格相关的记录。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-09-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多