代码之家  ›  专栏  ›  技术社区  ›  Andrzej Doyle

或约束的SQL语句中的条件列

  •  1
  • Andrzej Doyle  · 技术社区  · 16 年前

    这个问题是关于SQL中的一种通用技术,我不太清楚如何用我目前对该语言的理解来最好地实现这一点。

    请注意,这将针对Oracle运行,以防任何特定于供应商的功能特别有用,尽管我希望有一种使用“纯”SQL的好方法。

    问题的简短版本:如果我在一个查询中有一个或条件,以便检查“主”表A中的值是否与表B或表C中的值对应,那么如果在表C中找到了值,但没有在表B中找到值,那么有条件地修改(例如乘法)语句选择器的最佳方法是什么?

    长版本(举个例子):目前我有一个大致类似这样的查询(它要复杂得多,但这是基本结构):

    select o.value, /* other stuff... */
      from orders o,
           clients c
     where o.client = c.pkey
       and c.name = ?
    

    一切都很好。然而,现在想象一下,有些客户可以代表其他客户行事——但是由于处理费用或以这种方式进行的某些逻辑交易没有完全价值。所以有一张桌子 managed_orders 列用于 order , client (各表的两个主键)和另一列 multiplier ,这是一个介于0.0和1.0之间的浮点数,表示应“执行”的订单值的比例。

    对-因此,修改上述查询以显示由给定客户机拥有或由他们为其他人管理的订单是相当简单的。但是,我需要乘以 o.value 按托管订单的选择器 乘数 如果 这是一个托管订单,但是如果它是一个经典的直接订单,那么就不需要这样做(或者等价地,我们可以乘以1.0)。

    select o.value * m.multiplier /* Will not work in all cases */, /* other stuff... */
      from orders o,
           clients c,
           managed_orders m
     where (o.client = c.pkey or m.order = o.pkey)
       and c.name = ?
       and m.client = c.pkey
    

    如何最好地实现这个条件乘法?

    4 回复  |  直到 16 年前
        1
  •  5
  •   Tony Andrews    16 年前

    如果不是所有订单都有关联的托管订单,则需要使用外部联接。然后,您可以处理缺少这样一个乘数的问题:

    select o.value * COALESCE(m.multiplier,1)
    from orders o
    left outer join managed_orders m on m.order = o.pkey
    left outer join clients c on (o.client = c.pkey or m.client = c.pkey)
    where c.name = ?
    

    合并确保如果没有乘数,则使用常量1。

        2
  •  2
  •   Vincent Malgrat    16 年前

    你可以用一个 OUTER JOIN 把两个表连接起来。假设所有订单都有一个客户,并且只有托管订单存在于 MANAGED_ORDERS 表中,只有当修饰符是托管订单时,才会应用修饰符:

    SELECT o.value * nvl(m.multiplier, 1)
      FROM orders o
      JOIN client c ON (o.client = c.pkey)
      LEFT JOIN managed_orders ON o.pkey = m.order
    WHERE c.name = ?
    
        3
  •  2
  •   Tom Brown    16 年前

    你能用union得到所需的结果集吗?

    类似的东西

    Select o.value, ... 
    FROM Orders o, clients c
    WHERE o.client = c.pkey
    and c.name = ?
    UNION
    SELECT o.value * m.multiplier, ...
    FROM Orders o, clients c, managed_orders m
    WHERE m.order = o.pkey
    AND c.name = ?
    AND m.client = c.pkey
    
        4
  •  1
  •   Dirk    16 年前

    情况怎么样?

    SELECT o.value * (CASE 
                         WHEN m.pkey IS NOT NULL THEN m.managed_multiplier /* Might need */
                         ELSE 1.0                                  /* some tweaking here */ 
                     END)
        /* , other stuff... */
    FROM orders o
        LEFT JOIN clients c ON (o.client = c.pkey)
            LEFT JOIN managed_orders m ON (m.order = o.pkey)
    WHERE 
       c.name = ?