【问题标题】:Mysql Select record where PRIMARY key = xMysql 选择 PRIMARY key = x 的记录
【发布时间】:2011-06-14 21:05:08
【问题描述】:

我的 mysql 表中有一个主键,它由三列组成。

CREATE TABLE IF NOT EXISTS `bb_bulletin` (
  `OfficeCode` int(5) NOT NULL,
  `IssuerId` int(11) NOT NULL,
  `BulletinDtm` datetime NOT NULL,
  `CategoryCode` varchar(4) NOT NULL,
  `Title` varchar(255) NOT NULL,
  `Content` text NOT NULL,
  PRIMARY KEY (`OfficeCode`,`IssuerId`,`BulletinDtm`),
  UNIQUE KEY `U_IssuerId` (`IssuerId`,`OfficeCode`,`BulletinDtm`),
  UNIQUE KEY `U_CategoryCode` (`CategoryCode`,`OfficeCode`,`IssuerId`,`BulletinDtm`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;

是否有一种速记方法可以为给定的主键值选择记录。

我试过了。

SELECT * FROM `bb_bulletin` WHERE PRIMARY = '20001-1-2011-01-07 14:04:40'

而不是长手的做法,

SELECT * From bb_bulletin WHERE OfficeCode = 20001 AND IssuerId = 1 AND BulletinDtm = 2011-01-07 14:04:40

在您的表中处理 php 和复合键时的标准是什么。 注意:我不想在我的表中添加自动递增键来解决这个问题。如果不可能,那么我将在我的 url 中传递三个约束。

【问题讨论】:

    标签: mysql composite-primary-key


    【解决方案1】:

    我看到你的问题有两个部分。第一部分是关于引用复合值。我不确定 MySQL 是否支持这一点,但这将是 SQL 标准的执行方式:

    SELECT * FROM bb_bulletin WHERE (OfficeCode, IssuerId, BulletinDtm) = (20001, 1, '2011-01-07 14:04:40');
    

    另一部分是使用缩写语法引用主键列。我不知道有这种可能性。

    【讨论】:

    • MySQL 确实支持这种语法(至少在 5.2 中)
    • 我只是在为我认为的完成方式编造语法,但如果可行,您在上面提供的内容看起来像是一个很好的速记方法。谢谢我试一试。
    • 你在这里所做的事情有名字吗?即将列指定为逗号分隔列表,然后将值指定为逗号分隔列表?
    • 这是否会像下面建议的那样引起问题?
    • 一些非 SQL 可能支持这一点,以缓解 OP 正在寻求帮助的 php 问题,但它绝对不是标准 SQL。
    【解决方案2】:

    不,在 MySQL 或我知道的任何 SQL 方言中都没有这种方法。

    您应该在 PHP 中拆分 20001-1-2011-01-07 14:04:40 字符串并使用它的部分来构建您的 MySQL 查询。

    我还可以补充一点,复合主键在性能方面可能不是最好的主意(尤其是 InnoDB 表)

    此外,INT(5) 占用的空间仍与INT(11) 一样多(或者在这方面是普通的INT)。对于较小的整数类型,请使用 TINYINTSMALLINTMEDIUMINT


    笨拙的解决方法部分

    以下解决方案应按您希望的方式工作,但会以资源和/或性能为代价。除非您真的无法采用最简单的解决方案,否则您不应该使用这些。


    一个可怕的方法是这样的 WHERE CONCAT(OfficeCode,IssuerId,BulletinDtm) = '20001-1-2011-01-07 14:04:40'

    这是HORRIBLE,因为它不允许 MySQL 使用索引来实际加速查询。

    请不要这样做。


    另一种方式。将CHAR(32) 列添加到您的表中并使其成为您的PK。在其中存储您以前的 PK 列的 MD5 哈希(即 MD5('20001-1-2011-01-07 14:04:40')。然后您可以查询:WHERE newPKcolumn = MD5('20001-1-2011-01-07 14:04:40')。这将允许您做什么您想要,MySQL 使用索引。该表不再规范化,但非规范化是您有时需要做的权衡,以提高性能或可用性。这没有什么问题。

    【讨论】:

    • 嗯,就应用程序而言,它使复合键有点让人头疼,因为当您想要定位特定元素时,您需要一个类似的链接。 index.php?action=someaction&OfficeCode=x&IssuerId=y&BulletinDtm=z
    • 除了“不,不是真的”之外,没有什么可说的了。我会说我想不出任何人愿意这样做的充分理由,要么 8-|另外:就我个人而言,为了简单起见,我一直坚持使用单列自动增量主键(对其他值使用唯一键,就像操作已经在做的那样)
    • 或者您需要一段代码,它将 URL 中给出的 PK 值拆分为复合部分。
    • 如果您不使用复合主键,则很难/不可能标准化您的数据库。
    • 必须有一个标准的方式来使用 mysql 和 php 应用程序中的复合键。
    【解决方案3】:

    您可以创建一个将'20001-1-2011-01-07 14:04:40'(字符串)作为参数的存储过程,然后对其进行解析并在过程中创建SELECT 语句。

    【讨论】:

    • 我以前从未做过这样的事情。您能否再描述一下该过程,以便我对此进行研究?
    • 你可以这样做,但它会过于复杂并增加不必要的低效率。你试图做的不是一个好主意,安德鲁。如果要传递单个字符串,请在构建查询之前在代码中解析该字符串。
    • 如果无法使用主键进行速记选择,那么我将在 url 中传递所有三个参数。
    【解决方案4】:

    不可能那样做。预解析的存储过程是完成此任务的一种方法。如果您不必坚持此表设计,我建议将主键更改为可以设置为自动增量的新列。

    如果您必须坚持这种设计,那么您仍然可以添加一个新的“映射”表,顾名思义,它将您的组合映射到主键:

    CREATE TABLE IF NOT EXISTS `bbb_mapping` (
      `YourPK` int(11) NOT NULL AUTO_INCREMENT,
      `OfficeCode` int(5) NOT NULL,
      `IssuerId` int(11) NOT NULL,
      `BulletinDtm` datetime NOT NULL
      PRIMARY KEY (`YourPK`)
    ) ENGINE=MyISAM DEFAULT CHARSET=latin1;
    

    使用这种方法,您可以在查询字符串中使用 YourPK 时将映射表与原始表连接起来。

    干杯

    【讨论】:

    • 这是一个有趣的建议。如果主键是唯一的并且其他三个列包含一个唯一键,那么这与使用自动递增主键创建另一列相同。
    • 这正是我们的想法:D。根据您的表名,我假设您正试图侵入 PHPBB 公告板。在该表中添加自动增量并更改主键可能会破坏项目(想想外键),或者您可能必须对代码进行数十次更改。如果您的唯一目标是最小化 url/querystring,那么这似乎是一个不错的解决方法,而不会有破坏事物的风险。
    猜你喜欢
    • 2011-04-20
    • 1970-01-01
    • 2014-12-17
    • 2011-09-25
    • 1970-01-01
    • 1970-01-01
    • 2010-11-12
    • 2012-01-04
    相关资源
    最近更新 更多