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

具有动态列数的PostgreSQL查询

谷德本
2023-03-14
问题内容

我试图找到一种方法来返回具有动态列数的记录集。我可以编写一个查询来生成需要的列名列表,如下所示:

SELECT DISTINCT name FROM tests WHERE group = 'basic';

这将返回一个简短的列表,例如’poke’,’prod’,’hit’,’drop’等。然后,我希望生成一个表,其中显示了一系列测试,其中每个测试都在其中运行。每天早晨,我们查看开发人员的工作并对其进行戳戳和刺戳,以便每天进行每次测试。我可以静态编写此查询:

SELECT (SELECT success FROM test_results AS i
        WHERE i.name = 'poke'
        AND i.date = o.date) AS 'poke',
       (SELECT success FROM test_results AS i
        WHERE i.name = 'prod'
        AND i.date = o.date) AS 'prod',
...
FROM test_results AS o GROUP BY date
HAVING date > now() - '1 week'::interval;

但是,这是硬编码到我们每天运行的测试中的。如果现在我们需要每天开始踢设备,则需要更新查询。如果我们决定不再需要下降测试,则一周后,下降测试列应删除报告,因为它不再出现在结果中。当只有某些日期有结果条目时,对于缺少的测试返回NULL是完全可以接受的。

是否有一种方法可以通过仅在查询中使用常规SQL来从结果中创建动态列列表?

我试图通过使用WITH查询来构建部分所需的数据,但是我找不到从动态信息正确构建最后一行的方法。

编辑: 这是最近两天的一些示例数据:

CREATE TABLE test_results (
    name TEXT NOT NULL,
    date DATE default now() NOT NULL,
    success BOOLEAN NOT NULL
);

INSERT INTO test_results (name, date, success) VALUES ('hit',  '2017-06-20', TRUE);
INSERT INTO test_results (name, date, success) VALUES ('poke', '2017-06-20', TRUE);
INSERT INTO test_results (name, date, success) VALUES ('prod', '2017-06-20', TRUE);

INSERT INTO test_results (name, date, success) VALUES ('poke', '2017-06-21', TRUE);
INSERT INTO test_results (name, date, success) VALUES ('prod', '2017-06-21', TRUE);

INSERT INTO test_results (name, date, success) VALUES ('poke', '2017-06-22', TRUE);
INSERT INTO test_results (name, date, success) VALUES ('prod', '2017-06-22', FALSE);

INSERT INTO test_results (name, date, success) VALUES ('poke', '2017-06-23', TRUE);
INSERT INTO test_results (name, date, success) VALUES ('prod', '2017-06-23', TRUE);
INSERT INTO test_results (name, date, success) VALUES ('drop', '2017-06-23', TRUE);

如果我针对2017-06-21至2017-06-23的数据范围运行查询,则希望获得如下所示的结果,其中包括当时运行的所有测试的矩阵:

date        | poke   | prod   | drop
------------+--------+--------+-----
2017-06-21  | TRUE   | TRUE   | NULL
2017-06-22  | TRUE   | FALSE  | NULL
2017-06-23  | TRUE   | TRUE   | TRUE

名称戳,针刺和放置都是在该时间段内在行的名称字段中找到的所有名称。对于没有该日期记录的任何测试,将为详细查询返回NULL。


问题答案:

使用了不同的方法,这里已经提到了一些方法,例如交叉表。另外,您可以构建自己的函数,该函数可以动态构建查询并以TABLE和其他几种方法返回。

但是,所有这些都要求您预定义输出及其数据类型的确切数量。

如果我了解您的情况,那么您就不会像您提到的那样:

如果现在我们需要每天开始踢设备,则需要更新查询。

使用交叉表和其他方式的缺点几乎相同。

因此,有一种使用Cursors的方法。这可能不是最好的方法,如果可以使用crosstab,那可能更好。
但是至少这是我将在代码中添加注释的选项。

解决方案:

-- Function for opening cursor
CREATE OR REPLACE
FUNCTION    test_stats(
                c REFCURSOR,    -- cursor name
                sdate date,     -- start date of period wanted (included)
                edate date,     -- end date of period wanted (included)
                gtype text      -- you had in your 'tests' table some group type which I included just in case
            )
RETURNS     REFCURSOR
LANGUAGE    PLPGSQL
AS
$main$
BEGIN
    OPEN    c
    FOR
    -- Following dynamic query building can be
    -- used also if want to go with function that RETURNS TABLE
    EXECUTE format(
            '   SELECT  r.date,
                        %s
                FROM    test_results r
                WHERE   r.date BETWEEN %L AND %L
                GROUP BY 1
            ',
                -- Here we build for each 'name' own statement and 
                -- aggregate together with comma separator to feed
                -- into main query.
                -- P.S. We need to double check result unfortunately
                --      against test_results table once to get pre-filter
                --      for names in specified date range.
                --      With this we eliminate tests that for sure will
                --      not be presented in the range. In given test data
                --      this means eliminating 'hit'.
            (
                SELECT  string_agg(
                            DISTINCT format(
                                '(  SELECT  success
                                    FROM    test_results i
                                    WHERE   i.name = %1$L
                                    AND     i.date = r.date ) AS "%1$s"',
                                t.name
                            ),
                            ','
                        )
                FROM    tests t,
                LATERAL (   SELECT  array_agg( DISTINCT r.name )
                            FROM    test_results r
                            WHERE   r.date BETWEEN sdate AND edate
                        ) a( lst )
                WHERE   t.group = gtype     -- the group type is used here
                AND     t.name = ANY ( a.lst::text[] )
            ),
            sdate,      -- start date for between statement
            edate       -- end date for between statement
        );
    RETURN c;
END;
$main$;

-- Usage example:
BEGIN;
SELECT test_stats( 'teststats1', '2017-06-21'::date, '2017-06-23'::date, 'basic' );
FETCH ALL IN teststats1;
COMMIT;

-- Result (from your given test data set):
    date    | drop | poke | prod
------------+------+------+------
 2017-06-22 |      | t    | f
 2017-06-21 |      | t    | t
 2017-06-23 | t    | t    | t
(3 rows)

正如我所提到的,这不是完美的方法,但是它确实可以完成工作:)



 类似资料:
  • 问题内容: 我已经徒劳地搜索了很长时间,不得不承认失败并寻求帮助,我正在尝试修改数据透视查询,以从具有以下数据的表中生成结果的动态查询: 为了显示这样的内容,其中页码列取决于用户访问的页面数: 我已经通过对列中的硬编码进行了管理,但是显然我不想继续更改脚本以容纳越来越多的页面。 到目前为止,我有一些类似的东西: 任何帮助或正确方向的指点将不胜感激! 提前致谢! 问题答案: 我所看到的关于动态枢轴的

  • 问题内容: 我在SQL Server中使用交叉表查询时遇到问题。 假设我有以下数据: 我想查询显示结果如下: 我如何查询以显示这样的输出? 笔记: 主题名称: C C ++ 英语 数据库 数学 将根据学生学习的学科而有所不同。 请访问http://sqlfiddle.com/#!6/2ba07/1来测试此查询。 问题答案: 有两种方法可以执行对值进行硬编码的静态方法和执行时确定列的动态方法。 即使

  • 问题内容: 我有下面的代码,我在布尔查询中做多个必须的。在这里,我将在字段“地址”中传递必填项查询。现在,该IP地址将以其他api的列表的形式出现在我的面前,我必须将列表中的所有IP作为必填项查询传递给我。在这里,我没有办法创建QueryBuilder时如何动态传递地址值。 请提出建议。 问题答案: 您可以使用条件查询为单个字段传递多个值。创建一个字符串数组或集合。并将其传递给条款查询。 希望能帮

  • 问题内容: 与先前 的一对一映射问题 类似,我需要一个针对源和目标中多列的解决方案。 仍可与Postgres 9.4.4一起使用,对查询和架构进行了修改,如下所示: 假设我有这两个表和: 还有另一个表,用于存储将数据从迁移到的公式: 如何在动态查询中编译此公式并将其插入目标表? 问题答案: 动态查询多列语句的基本查询-忽略该列: 结果: 这假定了一个 _ 单一的 源和一个 _ 单一的 目标表。否则

  • 问题内容: 我是Postgres的新手,我不知道如何将此MySQL查询转换为Postgres: 问题答案: Postgres全文搜索与MySQL全文搜索略有不同。它有更多选择,但要以您喜欢的方式工作可能会更加困难。 该文档告诉您如何对搜索结果进行排名,但是我强烈建议您阅读手册的全文部分,以了解如何使用它:http : //www.postgresql.org/docs/current/ Inter

  • 我想创建一个java程序,它接受动态数量的参数。例如: 其中可能会有所不同。 我使用Commons CLI作为命令行选项解析器。但我找不到一种方法来实现一个接受动态参数数的选项。 setArgs指定选项必须接受的参数数。是否可以指定选项可以接受的最小参数数? 或者我应该使用其他工具来解析命令行选项?