银河对《SQL反模式》的笔记(9)

SQL反模式
  • 书名: SQL反模式
  • 作者: [美] Bill Karwin
  • 页数: 253
  • 出版社: 人民邮电出版社
  • 出版年: 2011-9
  • 第25页 第3章 单纯的树 第5节 解决方案:使用其他树模型
    SELECT *
    FROM Comments AS c
    WHERE '1/4/6/7/' LIKE c.path || '%';

    应该可以改为:

    SELECT *
    FROM Comments
    WHERE '1/4/6/7/' LIKE path || '%';

    还有,接着的:

    SELECT *
    FROM Comments AS c
    WHERE c.path LIKE '1/4/' || '%';
    这句查询语句所找到的后代路径分别是 1/4/5、1/4/6 以及 1/4/6/7。
    引自 第3章 单纯的树 第5节 解决方案:使用其他树模型

    也可以改为:

    SELECT *
    FROM Comments AS c
    WHERE path LIKE '1/4/%';

    后代路径似乎应该还要加上 1/4/。

    2012-04-28 23:14:06 2回应
  • 第15页 第2章 乱穿马路 第5节 解决方案:创建一张交叉表
    INSERT INTO Contacts (prouct_id, account_id)
    VALUES (123, 12), (123, 34), (345, 23), (567, 12), (567, 34);

    这种在一条 INSERT 语句中插入多录记录的 SQL 语句还是第一次见到,又学了一招。

    2012-04-29 00:23:06 1回应
  • 第77页 第8章 多列属性 第2节 反模式:创建多个列
    在多个列中查找一个值的语法是冗长乏味的。你可以通过一种非传统的方式来使用 IN,从而使得这个查询变得更加精简:
    引自 第8章 多列属性 第2节 反模式:创建多个列
    SELECT * FROM Bugs
    WHERE 'performance' IN (tag1, tag2, tag3)
      AND 'printing' IN (tag1, tag2, tag3);

    注:tag1、tag2 和 tag3 是 Bugs 表中的列。 这个非传统的方式很有趣。 :)

    2012-04-29 21:21:23 回应
  • 第131页 第14章 对未知的恐惧 第5节 解决方案:将NULL视为特殊值
    类似地,用户不能直接输入一个NULL。程序的输入端可能会使用一些特殊处理来引导用户输入NULL。比如,微软的.NET 2.0及以上版本,为Web界面提供了一个叫做ConvertEmptyStringToNull的方法。参数和绑定字段会自动地将空字符串转换成NULL。
    引自 第14章 对未知的恐惧 第5节 解决方案:将NULL视为特殊值

    这是不正确的。实际上,ConvertEmptyStringToNull 不是方法,而是 System.Web.UI.WebControls.Parmeter 类的属性,请参见:http://msdn.microsoft.com/zh-cn/library/system.web.ui.webcontrols.parameter.convertemptystringtonull.aspx

    Parameter.ConvertEmptyStringToNull 属性:获取或设置一个值,该值指示在 Parameter 对象绑定到的值为 String.Empty 时是否应将其转换为 null。 语法:public bool ConvertEmptyStringToNull { get; set; } 属性值:类型:System.Boolean。如果在 Parameter 绑定到的值为 String.Empty 时应将其转换为 null,则为 true;否则为 false。 默认值为 true。
    引自 第14章 对未知的恐惧 第5节 解决方案:将NULL视为特殊值

    很明显,ConvertEmptyStringToNull 属性是一个标志,用于指示是否应该将空字符串转换成NULL,而不是用于将空字符串转换为NULL的方法。

    2012-04-30 19:23:55 回应
  • 第159页 第17章 可怜人的搜索引擎 第5节 解决方案:使用正确的工具
    CREATE TABLE Keywords (
      keyword_id SERIAL PRIMARY KEY,
      keyword    VARCHAR(40) NOT NULL,
      UNIQUE KEY (keyword)
    )

    以及:

    CREATE PROCEDURE BugsSearch(keyword VARCHAR(40))
    BEGIN
      SET @keyword = keyword;
      PREPARE s1 FROM 'SELECT MAX(keyword_id) INTO @k FROM Keywords WHERE keyword = ?';
      EXECUTE s1 USING @keyword;
      DEALLOCATE PREPARE S1;
      IF (@k IS NULL) THEN
        -- (这里省略若干语句)
      END IF;
      -- (这里再次省略若干语句)
    END

    注意 Keywords 表的 keyword 列上有 unique 索引,查询结果不可能多于一行,但是上述存储过程还是使用了 MAX() 函数。这是为避免返回空结果集。请参见:http://www.cnblogs.com/skyivben/archive/2012/04/30/2476937.html

    2012-04-30 19:35:18 回应
  • 第160页 第17章 可怜人的搜索引擎 第5节 解决方案:使用正确的工具
    ①搜索用户指定关键字。从 keywords、keyword_id 或 NULL 返回整型主键,如果这个词之前未出现过。
    引自 第17章 可怜人的搜索引擎 第5节 解决方案:使用正确的工具

    这段话有误,应改为: ①搜索用户指定关键字。如果搜索成功,则从 Keywords 表中返回其整型主键 keyword_id 的值。如果这个词之前未出现过,则返回NULL。

    2012-04-30 19:43:55 回应
  • 第164页 第18章 意大利面条式查询 第2节 反模式:使用一步操作解决复杂问题

    该页的 图18-1 被修复与打开Bug的笛卡儿积 的左边的 bug_id 只有11个,而根据上下文,应该有12个 bug_id 才对。

    2012-04-30 19:48:31 回应
  • 第184页 第20章 明文密码 第5节 解决方案:先哈希,后存储

    第182页:

    比如,SHA-256 算法将我们的密码 xyzzy,转换成了一个 256 位的串,若使用 16 进制表示是一个 64 字节的字符串。
    引自 第20章 明文密码 第5节 解决方案:先哈希,后存储

    这是不对的,应改为: 比如,SHA-256 算法将我们的密码 xyzzy,转换成了一个 256 位(bits)的串,需要 32 字节(bytes)的存储空间,可以表示为 64 个 16 进制数字(digits)。 第183页:

    下面是对 Accounts 表的重定义。SHA-256 的哈希密码总是一个 64 字节的字符串,因此这一列的类型是固定长度的 CHAR。
    引自 第20章 明文密码 第5节 解决方案:先哈希,后存储

    这也是不对的,应改为: 下面是对 Accounts 表的重定义。SHA-256 的哈希密码总是占用 32 字节(bytes)的存储空间,可以表示为 64 个 16 进制数字(digits),因此这一列的类型是固定长度的 CHAR。 第183页:

    比如,MySQL 6.0.5 的 SSL 扩展支持包含了 SHA2() 的函数,它默认返回一个 256 位的哈希串。
    引自 第20章 明文密码 第5节 解决方案:先哈希,后存储

    截止目前(2012-04-30)为止,MySQL Community Server 的最新稳定版本是 Generally Available (GA) Releases 5.5.23,最新开发版本是 Development Releases 5.6.5 m8。作者写这本书时,哪里来的 MySQL 6.0.5? 第184页:

    CREATE TABLE Accounts (
      account_id     SERIAL PRIMARY KEY,
      account_name VARCHAR(20),
      email       VARCHAR(100) NOT NULL,
      password_hash CHAR(32) NOT NULL,
      salt   BINARY(8) NOT NULL
    );

    上述代码中 password_hash 字段应该是 CHAR(64) 或者 BINARY(32) 类型才对。

    2012-04-30 20:07:26 回应
  • 第250页 附录A 规范化规则
    CREATE TABLE BugsAssigned (
      bug_id     BIGINT NOT NULL,
      assigned_to BIGINT NOT NULL,
      PRIMARY KEY (account_id, assigned_to),
      FOREIGN KEY (bug_id) REFERENCES Bugs(bug_id),
      FOREIGN KEY (assigned_to) REFERENCES Accounts(account_id),
      FOREIGN KEY (product_id) REFERENCES Porducts(product_id)
    );

    这张表中多了一个外键约束,应改为:

    CREATE TABLE BugsAssigned (
      bug_id     BIGINT NOT NULL,
      assigned_to BIGINT NOT NULL,
      PRIMARY KEY (account_id, assigned_to),
      FOREIGN KEY (bug_id) REFERENCES Bugs(bug_id),
      FOREIGN KEY (assigned_to) REFERENCES Accounts(account_id)
    );
    2012-04-30 22:05:31 回应