当前位置: 首页 > 面试题库 >

健壮的方法以编程方式构建SQL查询

龙逸清
2023-03-14
问题内容

我不得不求助于ORM不足的原始SQL(使用Django
1.7)。问题在于大多数查询最终都具有80-90%的相似性。在不违反可重用性的前提下,我无法找到一种可靠且可靠的方式来构建查询。

字符串连接是唯一的出路,即使用if- else条件构建无参数查询字符串,然后使用准备好的语句安全地包含参数(以避免SQL注入)。我想采用一种简单的方法来为我的项目模板SQL,而不是重新发明一个小型ORM。

例如,考虑以下查询:

SELECT id, name, team, rank_score
FROM
  ( SELECT id, name, team
    ROW_NUMBER() OVER (PARTITION BY team
                       ORDER BY count_score DESC) AS rank_score
    FROM 
      (SELECT id, name, team
       COUNT(score) AS count_score
       FROM people
       INNER JOIN scores on (scores.people_id = people.id)
       GROUP BY id, name, team
      ) AS count_table
  ) AS rank_table
WHERE rank_score < 3

我怎样才能:

a)在上添加可选WHERE约束,people
b)更改INNER JOINLEFT OUTER
c)更改COUNTSUM
d)完全跳过该OVER / PARTITION条款?


问题答案:

更好的查询

对于初学者,您可以修复语法,简化和澄清很多:

SELECT *
FROM  (
   SELECT p.person_id, p.name, p.team, sum(s.score)::int AS score
         ,rank() OVER (PARTITION BY p.team
                       ORDER BY sum(s.score) DESC)::int AS rnk
    FROM  person p
    JOIN  score  s USING (person_id)
    GROUP BY 1
   ) sub
WHERE  rnk < 3;
  • 建立在我更新的表格布局上。参见下面的小提琴。

  • 您不需要其他子查询。窗口函数是 集合函数 之后 执行的,因此您可以像演示的那样嵌套它。

  • 在谈论“等级”时,您可能想使用rank()而不是row_number()

  • 假设people.people_id是PK,则可以简化GROUP BY

  • 确保对所有可能不明确的列名进行表限定

PL / pgSQL函数

然后,我将编写一个plpgsql函数,该函数接受可变部分的参数。实施a-c您的观点。d尚不清楚,请留待您补充。

CREATE OR REPLACE FUNCTION f_demo(_agg text       DEFAULT 'sum'
                               , _left_join bool  DEFAULT FALSE
                               , _where_name text DEFAULT NULL)
  RETURNS TABLE(person_id int, name text, team text, score int, rnk int) AS
$func$
DECLARE
   _agg_op  CONSTANT text[] := '{count, sum, avg}';  -- allowed functions
   _sql     text;
BEGIN

-- assert --
IF _agg ILIKE ANY (_agg_op) THEN
   -- all good
ELSE
   RAISE EXCEPTION '_agg must be one of %', _agg_op;
END IF;

-- query --
_sql := format('
SELECT *
FROM  (
   SELECT p.person_id, p.name, p.team, %1$s(s.score)::int AS score
         ,rank() OVER (PARTITION BY p.team
                       ORDER BY %1$s(s.score) DESC)::int AS rnk
    FROM  person p
    %2$s  score  s USING (person_id)
    %3$s
    GROUP BY 1
   ) sub
WHERE  rnk < 3
ORDER  BY team, rnk'
   , _agg
   , CASE WHEN _left_join THEN 'LEFT JOIN' ELSE 'JOIN' END
   , CASE WHEN _where_name <> '' THEN 'WHERE p.name LIKE $1' ELSE '' END
);

-- debug   -- quote when tested ok
-- RAISE NOTICE '%', _sql;

-- execute -- unquote when tested ok
RETURN QUERY EXECUTE _sql
USING  _where_name;   -- $1

END
$func$  LANGUAGE plpgsql;

称呼:

SELECT * FROM f_demo();
SELECT * FROM f_demo('sum', TRUE, '%2');    
SELECT * FROM f_demo('avg', FALSE);
SELECT * FROM f_demo(_where_name := '%1_'); -- named param

SQL小提琴

  • 您需要对PL / pgSQL有深入的了解。否则,有太多需要解释的地方。您可以在plpgsql下的SO上找到相关答案,几乎可以找到答案中的每个细节。


 类似资料:
  • 问题内容: 我正在尝试根据从表单接收的输入来构建搜索。 我想根据这些值建立一个查询,但是如果该字段没有值,我显然不想在搜索中包括它(搜索“”会改变结果) 我尝试了几种不同的方法,例如构建一个字符串以放置在其中: 但这似乎无法正常工作。我也尝试过像这样的“堆叠”搜索查询: 然后像这样执行搜索: 但这会导致500个错误(而且我不确定是否可以从中获取更多信息)。 请帮助新手动态建立猫鼬搜索查询:( 问题

  • Unix 至少设立了三层内部边界来防范恶意用户或有缺陷的程序。一层是内存管理:Unix 用硬件自身的内存管理单元(MMU)来保证各自的进程不会侵入到其它进程的内存地址空间。第二层是为多用户设置的真正权限组——普通用户(非 root用户)的进程未经允许,就不能更改或者读取其他用户的文件。第三层是把涉及关键安全性的功能限制在尽可能小的可信代码块上。在 Unix 中,即使是 shell(系统命令解释器)

  • 问题内容: 我一直在尝试以编程方式重做我的应用程序上的工作。(不使用情节提要) 除了手动制作导航控制器外,我几乎完成了。 我一直在做一些研究,但找不到任何手动实现此方法的文档。(我开始将应用程序制作为单视图应用程序) 目前,我只有1个ViewController。当然是appDelegate 导航控制器将在应用程序的所有页面中使用。 如果有人可以帮助我,或发送指向一些适当文档的链接以编程方式进行此

  • 问题内容: 我将C#与SMO一起使用,并尝试检测要连接到的SQL Server版本(例如,企业版,标准版)。我知道如何获取版本信息,但这只能告诉我SQL Server的版本(例如,SQL Server 2008与SQL Server 2005)。 有谁知道如何获得实际的产品版本(例如,企业版,标准版)? 我需要此信息,因为某些SQL Server功能只是企业级的。因此,我可以尝试调用它们并捕获异常

  • 第7章讲解了Erlang的错误处理机制。这一章我们来看看怎样使用这些机制来构建健壮、容错的系统。 防范错误数据 回想一下在第??章(程序??.5)中描述的那个用来分析电话号码的服务程序。它的主循环包含了以下代码: server(AnalTable) -> receive {From, {analyse,Seq}} -> Result = lookup

  • 问题内容: 有没有一种方法可以在Windows中创建链接? 我发现使用的样本或必须下载的样本。 我需要一个简单的解决方案。那可能吗? 问题答案: 好了,我不得不使用创建快捷方式的方法,但是实际上我需要的是一个文件夹,但是会创建一个。 最终我用来创建。