【问题标题】:Pass In "WHERE" parameters to PostgreSQL View?将“WHERE”参数传递给 PostgreSQL 视图?
【发布时间】:2012-07-09 05:55:28
【问题描述】:

我的 PostgreSQL 数据库有一个相当复杂的查询,通过一系列嵌套子查询跨越 4 个表。然而,尽管外观和设置看起来有点棘手,但最终它将基于两个外部参数的匹配(两个字符串需要与不同表中的字段匹配)返回两列(来自同一个表,如果这有助于这种情况)。我对 PostgreSQL 中的数据库设计相当陌生,所以我知道这个看似神奇的东西叫做 Views 存在,它似乎可以帮助我,但也许没有。

有什么方法可以将我的复杂查询移动到视图中,并以某种方式将我需要匹配的两个值传递给它?这将大大简化我在前端的代码(通过将复杂性转移到数据库结构上)。我可以创建一个包含我的静态示例查询的视图,它工作得很好,但是只适用于一对字符串值。我需要能够将它与各种不同的值一起使用。

因此,我的问题是:是否可以将参数传递到其他静态视图并使其变为“动态”?或者也许视图不是处理它的正确方法。如果还有其他更好的方法,我会全力以赴!

*编辑:* 根据 cmets 的要求,这是我现在的查询:

SELECT   param_label, param_graphics_label
  FROM   parameters
 WHERE   param_id IN 
         (SELECT param_id 
            FROM parameter_links
           WHERE region_id = 
                 (SELECT region_id
                    FROM regions
                   WHERE region_label = '%PARAMETER 1%' AND model_id =
                         (SELECT model_id FROM models WHERE model_label = '%PARAMETER 2%')
                 )
         ) AND active = 'TRUE'
ORDER BY param_graphics_label;

参数由上面的百分比符号设置。

【问题讨论】:

    标签: sql postgresql stored-procedures view


    【解决方案1】:

    你可以使用一个集合返回函数:

    create or replace function label_params(parm1 text, parm2 text)
      returns table (param_label text, param_graphics_label text)
    as
    $body$
      select ...
      WHERE region_label = $1 
         AND model_id = (SELECT model_id FROM models WHERE model_label = $2)
      ....
    $body$
    language sql;
    

    那么你可以这样做:

    select *
    from label_params('foo', 'bar')
    

    顺便说一句:你确定要:

    AND model_id = (SELECT model_id FROM models WHERE model_label = $2)
    

    如果model_label 不是唯一的(或主键),那么这最终会引发错误。你可能想要:

    AND model_id IN (SELECT model_id FROM models WHERE model_label = $2)
    

    【讨论】:

    • 您猜对了 model_label 不是主键。它“应该”是独一无二的,但这不一定是软件强制执行的。 (model_idmodels 的主键)。据我回忆,切换到 IN 应该不会损害我只想匹配一个条目这一事实,对吗?
    • @Devin:正确,如果您使用 IN,即使返回不止一行,它也会起作用。否则,您将在运行时收到错误消息。
    • 太棒了,这将完全按照我的需要工作。并且学到了一些关于 PostgreSQL 函数的很酷的东西。感谢您的帮助!
    【解决方案2】:

    除了@a_horse 已经清除的内容之外,您还可以通过使用JOIN syntax 而不是嵌套子查询来简化您的SQL。性能将相似,但语法更短且更易于管理。

    CREATE OR REPLACE FUNCTION param_labels(_region_label text, _model_label text)
      RETURNS TABLE (param_label text, param_graphics_label text) AS
    $func$
        SELECT p.param_label, p.param_graphics_label
        FROM   parameters      p 
        JOIN   parameter_links l USING (param_id)
        JOIN   regions         r USING (region_id)
        JOIN   models          m USING (model_id)
        WHERE  p.active
        AND    r.region_label = $1 
        AND    m.model_label = $2
        ORDER  BY p.param_graphics_label;
    $func$ LANGUAGE sql;
    
      1234563或者使用GROUP BY 子句。
    • 从 Postgres 9.2 开始,您可以在 SQL 函数中使用声明的参数名称代替 $1$2。 (PL/pgSQL 函数早就可以实现了)。

    • 必须小心避免命名冲突。这就是为什么我习惯在声明中为参数名称添加前缀(这些在函数中随处可见)并在正文中使用表限定列名称。

    • 我将WHERE p.active = 'TRUE' 简化为WHERE p.active,因为active 列很可能应该是boolean 类型,而不是text

    • USING 仅在列名在 JOIN 左侧的所有表中明确时才有效。否则,您必须使用更明确的语法:
      ON l.param_id = p.param_id

    【讨论】:

    • 哇哦,那好多了!我知道连接就在那里,并且对这个问题很方便,但我想我只是没有鼓起勇气尝试弄清楚如何在这里使用它。事实证明,它并没有那么糟糕!
    【解决方案3】:

    在大多数情况下,set-returning 函数是可行的方法,但如果您想同时读取和写入 set,视图可能更合适。 视图可以读取会话参数:

    CREATE VIEW widget_sb AS
      SELECT * FROM widget
      WHERE column = cast(current_setting('mydomain.myparam') as int)
    
    SET mydomain.myparam = 0
    select * from widget_sb
    [results]
    
    SET mydomain.myparam = 1
    select * from widget_sb
    [distinct results]
    

    【讨论】:

    • 无法设置 mydomain.myparam = _myownvariable;
    【解决方案4】:

    我认为您所说的“动态”视图是不可能的。

    为什么不写一个带有 2 个参数的存储过程呢?

    【讨论】:

      【解决方案5】:

      我会将查询改写如下:

      SELECT   p.param_label, p.param_graphics_label
        FROM   parameters p
      where exists (
          select 1
          from parameter_links pl
          where pl.parameter_id = p.id
          and exists (select 1 from regions r where r.region_id = pl.region_id
      ) and p.active = 'TRUE'
      order by p.param_graphics_label;
      

      假设您在各种 id 列上都有索引,这个查询应该比使用 IN 运算符快得多;这里的exists参数将只使用索引值,甚至不接触数据表,除了从参数表中获取最终数据。

      【讨论】:

        猜你喜欢
        • 2015-09-15
        • 2011-06-27
        • 2018-01-08
        • 2011-10-07
        • 2011-06-16
        • 1970-01-01
        • 2019-06-22
        • 2013-07-17
        • 2011-12-09
        相关资源
        最近更新 更多