创建一个有点复杂的笛卡尔结果

时间:2013-04-11 05:32:00

标签: sql postgresql

我有一个名为“where_clauses”的表,其中包含一系列我想用于构建动态查询的条件。我想知道我可以使用这些数据执行的所有可能的查询。这是我的“where_clauses”数据......

INSERT INTO where_clauses (id,col_name,clause) VALUES (1,'x','x < 1');
INSERT INTO where_clauses (id,col_name,clause) VALUES (2,'x','x < 2');
INSERT INTO where_clauses (id,col_name,clause) VALUES (3,'x','x < 3');
INSERT INTO where_clauses (id,col_name,clause) VALUES (4,'y','y < 1');
INSERT INTO where_clauses (id,col_name,clause) VALUES (5,'y','y < 2');
INSERT INTO where_clauses (id,col_name,clause) VALUES (6,'y','y < 3');
INSERT INTO where_clauses (id,col_name,clause) VALUES (7,'z','z < 1'); 

理想情况下,我希望以一系列ID形式提供“所有可能的查询”。例如,“所有可能的查询”结果将是......

{1}
{1,4}
{1,4,7}
{1,5}
{1,5,7}
{1,6}
{1,6,7}
{2}
{2,4}
{2,4,7}
{2,5}
{2,5,7}
{2,6}
{2,6,7}
{3}
{3,4}
{3,4,7}
{3,5}
{3,5,7}
{3,6}
{3,6,7}
{4}
{4,7}
{5}
{5,7}
{6}
{6,7}
{7}

请注意,即时抛出加入相等的列。什么是可以提供所有可能的where_clauses的查询?

3 个答案:

答案 0 :(得分:1)

这是new WITH RECURSIVE旨在解决的问题。以下内容适用于任意数量的列名称(不只是xyz)。

WITH RECURSIVE subq(a, x) AS
  ( VALUES (ARRAY[]::int[], NULL) /* initial */
    UNION ALL 
    SELECT subq.a || id, col_name FROM subq JOIN where_clauses
    ON x IS NULL OR x < col_name )
SELECT a FROM subq 
WHERE x IS NOT NULL;  /* discard the initial empty array */

答案 1 :(得分:0)

尝试此代码,它选择三列,那些未用于子句的列保留为NULL,您可以进一步连接或操作该结果:

--all possibilities with only one clause
SELECT
    id AS ID1, NULL ID2, NULL AS ID3
  FROM where_clauses
--all possibilities with two clauses (xy,xz,yz)
UNION
SELECT
    WC1.id AS ID1, WC2.id AS ID2, NULL AS ID3
  FROM where_clauses WC1
  CROSS JOIN where_clauses WC2
  WHERE
    WC1.col_name != WC2.col_name
    AND WC1.id > WC2.id
--all possibilities with an x and a y and a z clause
UNION
SELECT
    WC1.id AS ID1, WC2.id AS ID2, WC3.id AS ID3
  FROM where_clauses WC1
  CROSS JOIN where_clauses WC2
  CROSS JOIN where_clauses WC3
  WHERE
    WC1.col_name != WC2.col_name
    AND WC1.id > WC2.id

    AND WC1.col_name != WC3.col_name
    AND WC1.id > WC3.id

    AND WC2.col_name != WC3.col_name
    AND WC2.id > WC3.id

Here是一个小提琴。

编辑:略微修饰小提琴

答案 2 :(得分:0)

SELECT string_to_array(TRIM(x || ',' || y || ',' || z, ','), ',')
FROM (
WITH sq AS (
    SELECT a.id x, b.id y, c.id z
    FROM where_clauses a, where_clauses b, where_clauses c
    WHERE a.col_name != b.col_name AND
          a.col_name != c.col_name AND
          b.col_name != c.col_name AND
          a.id < b.id AND
          b.id < c.id
)
SELECT x, y, z FROM sq
UNION ALL
SELECT distinct x, y, null::int FROM sq
UNION ALL
SELECT distinct y, z, null::int FROM sq
UNION ALL
SELECT distinct x, null::int, null::int FROM sq
UNION ALL
SELECT distinct y, null::int, null::int FROM sq
UNION ALL
SELECT distinct z, null::int, null::int FROM sq
) ORDER BY 1;

以上查询可以帮助您吗?