【问题标题】:Pick column with default value or column with user defined value if not null?如果不为空,则选择具有默认值的列或具有用户定义值的列?
【发布时间】:2011-04-11 18:28:56
【问题描述】:

我正在开发一个 web 应用程序,其中包含一组用户可以浏览和编辑的数据。

用户希望自定义为每个项目显示的字段之一,例如“product_name”。

每个产品在一个表中都有一组默认值,对所有用户都是一样的:

产品表是这样的(跳过语法,你明白了):

CREATE TABLE products (
  pid     int,            # product id
  pname   varchar         # product name (users want to customize this)
);

只要有该产品的自定义值,我就需要在我网站上的所有表格/列表中显示用户的自定义产品名称,否则显示默认值。

为了节省空间,我考虑使用一个额外的表来“覆盖”任何给定用户、任何给定产品的默认值。行将根据需要添加到此表中。未自定义任何产品名称的用户将不会有任何行:

CREATE TABLE custom (
  pid     int,
  userid  int,
  pname   varchar
);

我可以轻松地在产品 ID 上加入这两个表,并且可以为 php 中的每一行选择默认值 (products.pname) 或用户编辑值 (custom.pname),但我希望有更多在 MySQL 中执行此操作的有效方法。

是否有一个表达式可以让我选择一列,如果不为空,则选择另一列(跨两个表)?

你会建议一种不同的方法来处理这个问题吗?

谢谢。

PS:也许是一种 JOIN 类型,它允许表 2 中具有相同名称的列覆盖表 1 中存在于表 2 中的那些行?

【问题讨论】:

    标签: php sql mysql schema


    【解决方案1】:

    看看 MySQL 的CASE-statement。这应该可以解决问题:

       SELECT CASE
                  WHEN `custom`.`pname` IS NULL
                  THEN `products`.`pname`
                  ELSE `custom`.`pname`
              END CASE AS `pname`
         FROM `products`
    LEFT JOIN `custom`
           ON `custom`.`pid` = `products`.`pid`
        WHERE `products`.`pid` = 123
    

    我没有对此进行测试,但它基本上应该是这样工作的。

    【讨论】:

    • 谢谢,无论如何要使用普通的 SELECT 查询来做到这一点?我还没有在这个应用程序上使用任何“存储程序”(存储过程?),并且还没有框架。
    • 感谢您在 SELECT 语句中突出显示 CASE。
    【解决方案2】:

    您正在寻找 COALESCE 函数。

    SELECT COALESCE(the_field, "This literal") FROM YOUR_TABLE
    

    如果 the_field 不为 null,则返回 the_field,否则为“This literal”。您可以根据需要混合字段和文字......所以 SELECT COALESCE(this_field, that_field) 也可以。你可以有两个以上的参数......例如SELECT COALESCE(this_field,that_field, theother_field)

    【讨论】:

    • 谢谢。我发现了一个类似的运算符,称为 IFNULL()。 IFNULL(expr1, expr2) 似乎等同于 COALESCE(expr1, expr2)。我不确定这个变体有什么用,因为 COALESCE() 可以接受两个以上的参数。
    • @faB: IFNULL 是 MySQL 特定的; COALESCE 是 ANSI 标准,可用于各种数据库。正如您所提到的,COALESCE 也可以采用两个以上的参数。大多数人建议尽可能使用 ANSI 语法。
    【解决方案3】:

    结合使用 LEFT JOIN 和 COALESCE:

       SELECT p.pid,
              COALESCE(c.pname, p.pname) AS product_name
         FROM PRODUCT p
    LEFT JOIN CUSTOM c ON c.pid = p.pid
                      AND c.userid = ?
    

    因为如果用户没有提供自定义名称,c.pname 将为 null,COALESCE 函数将默认使用下一个非 NULL 值——来自p.pname

    【讨论】:

      【解决方案4】:
      select if(c.pname is not null, c.pname, p.pname) pname
        from products p left outer join custom c on c.pid = p.pid;
      

      左外连接总是传递一个行匹配,如果连接失败,它将有空字段,你可以用 if() 函数测试。

      【讨论】:

      • 啊,我以为一定有三元运算符之类的东西。现在在参考手册中研究并合并并查看方法有何不同将会很有趣。谢谢!
      猜你喜欢
      • 1970-01-01
      • 2011-03-21
      • 2012-02-28
      • 2021-08-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-07-01
      • 1970-01-01
      相关资源
      最近更新 更多