来自多个表的PostgreSQL查询

时间:2017-08-03 19:23:37

标签: postgresql

关于查询PostgreSQL的问题 通过存储过程或任何编程语言可以很容易地完成,但我的问题是可以通过一个select语句来完成。这是两个表的一个例子。

enter image description here 谢谢。

2 个答案:

答案 0 :(得分:0)

您通常会在某种报告工具中执行“群组标题”。但是,如果您愿意,它可以在纯SQL中完成。

您从“标准加入”中的数据开始:

-- The basic query
SELECT
    table_1.table_1_id, phone, name, some_data, 
    row_number() over(partition by table_1.table_1_id order by some_data)
FROM
    table_1
    JOIN table_2 ON table_2.table_1_id = table_1.table_1_id ;

这将产生下表:

table_1_id | phone | name | some_data | row_number
---------: | :---- | :--- | :-------- | ---------:
         1 | 502   | aa   | a         |          1
         1 | 502   | aa   | b         |          2
         1 | 502   | aa   | j         |          3
         1 | 502   | aa   | n         |          4

         2 | 268   | bb   | a         |          1
         2 | 268   | bb   | s         |          2
         2 | 268   | bb   | y         |          3

         5 | 984   | ee   | a         |          1
         5 | 984   | ee   | n         |          2
         5 | 984   | ee   | w         |          3

如果你想添加一些标题行,并且不显示 phone, name, we need to *add* these data to the query. This is done by making a second specific SELECT for the headers, and UNION ALL`的值,第一个。

也就是说,我们将使用:

-- This query produces the 'headers'
SELECT DISTINCT
    table_1.table_1_id, 
    phone, 
    name, 
    '' AS some_data, 
    true as is_header   -- this marks this row as a 'header'
FROM
    table_1
    JOIN table_2 ON table_2.table_1_id = table_1.table_1_id

UNION ALL

-- This query produces the actual data
SELECT
    table_1.table_1_id, 
    phone,
    name, 
    some_data, 
    false as is_header
FROM
    table_1
    JOIN table_2 ON table_2.table_1_id = table_1.table_1_id ;

现在,我们将其作为 sub 查询,并制作一些额外的逻辑来决定需要显示哪些数据,以及需要隐藏哪些数据(实际上,显示为''):< / p>

-- A few tricks to do the formatting
SELECT
    -- Here we decide which information to show, which not
    case when is_header then cast(table_1_id as text) else '' end AS table_1_id,
    case when is_header then phone                    else '' end AS phone,
    case when is_header then name                     else '' end as name,
    case when is_header then ''                       else some_data end as some_data
FROM
    (-- This query produces the 'headers'
    SELECT DISTINCT
        table_1.table_1_id, 
        phone, 
        name, 
        '' AS some_data, 
        true as is_header   -- this marks this row as a 'header
    FROM
        table_1
        JOIN table_2 ON table_2.table_1_id = table_1.table_1_id
    UNION ALL
    -- This query produces the actual data
    SELECT
        table_1.table_1_id, 
        phone,
        name, 
        some_data, 
        false as is_header
    FROM
        table_1
        JOIN table_2 ON table_2.table_1_id = table_1.table_1_id
    ) AS q
ORDER BY
    q.table_1_id, is_header DESC /* Header goes first */, some_data ;

这会产生:

table_1_id | phone | name | some_data
:--------- | :---- | :--- | :--------
1          | 502   | aa   |          
           |       |      | a        
           |       |      | b        
           |       |      | j        
           |       |      | n        
2          | 268   | bb   |          
           |       |      | a        
           |       |      | s        
           |       |      | y        
5          | 984   | ee   |          
           |       |      | a        
           |       |      | n        
           |       |      | w        

您可以在 dbfiddle here

中查看整个设置和模拟数据

请注意,不会保留您指定的订单。你应该有一些关于如何订购的逻辑。 SQL没有“插入顺序”或“自然顺序”的概念;你总是要选择你想要的那个(否则,数据库将选择最方便的那个,并且可能从一次执行变为下一次执行)

答案 1 :(得分:0)

有一个很好的功能,如the documentation for FFmpeg here

使用它可以为单个查询/结果集获取不同分组条件的几个集合。感谢您提供的数据grouping sets

让我们从最简单的查询开始:

SELECT
  table_1.table_1_id, phone, name, some_data
FROM
  table_1 JOIN table_2 ON table_2.table_1_id = table_1.table_1_id;
┌────────────┬───────┬──────┬───────────┐
│ table_1_id │ phone │ name │ some_data │
╞════════════╪═══════╪══════╪═══════════╡
│          1 │ 502   │ aa   │ a         │
│          1 │ 502   │ aa   │ b         │
│          1 │ 502   │ aa   │ n         │
│          1 │ 502   │ aa   │ j         │
│          5 │ 984   │ ee   │ w         │
│          5 │ 984   │ ee   │ a         │
│          5 │ 984   │ ee   │ n         │
│          2 │ 268   │ bb   │ s         │
│          2 │ 268   │ bb   │ a         │
│          2 │ 268   │ bb   │ y         │
└────────────┴───────┴──────┴───────────┘

这里需要按前三列添加组:

SELECT
  table_1.table_1_id, phone, name--, some_data
FROM
  table_1 JOIN table_2 ON table_2.table_1_id = table_1.table_1_id
GROUP BY GROUPING SETS ((table_1.table_1_id, phone, name));
┌────────────┬───────┬──────┐
│ table_1_id │ phone │ name │
╞════════════╪═══════╪══════╡
│          2 │ 268   │ bb   │
│          5 │ 984   │ ee   │
│          1 │ 502   │ aa   │
└────────────┴───────┴──────┘

注意双括号。实际上它等于简单GROUP BY table_1.table_1_id, phone, name(因为我注释了some_data列,它不在组中)。但我们想在查询中添加更多数据:

SELECT
  table_1.table_1_id, phone, name, some_data
FROM
  table_1 JOIN table_2 ON table_2.table_1_id = table_1.table_1_id
GROUP By GROUPING SETS ((table_1.table_1_id, phone, name),(table_1.table_1_id, phone, name, some_data));
┌────────────┬───────┬──────┬───────────┐
│ table_1_id │ phone │ name │ some_data │
╞════════════╪═══════╪══════╪═══════════╡
│          1 │ 502   │ aa   │ a         │
│          1 │ 502   │ aa   │ b         │
│          1 │ 502   │ aa   │ j         │
│          1 │ 502   │ aa   │ n         │
│          1 │ 502   │ aa   │ ░░░░      │
│          2 │ 268   │ bb   │ a         │
│          2 │ 268   │ bb   │ s         │
│          2 │ 268   │ bb   │ y         │
│          2 │ 268   │ bb   │ ░░░░      │
│          5 │ 984   │ ee   │ a         │
│          5 │ 984   │ ee   │ n         │
│          5 │ 984   │ ee   │ w         │
│          5 │ 984   │ ee   │ ░░░░      │
└────────────┴───────┴──────┴───────────┘

这几乎是我们想要的。我们只需要以适当的方式订购数据并清理一些列:

SELECT
    case when some_data is null then table_1.table_1_id end as table_1_id,
    case when some_data is null then phone end as phone,
    case when some_data is null then name end as name,
    some_data
FROM
    table_1
    JOIN table_2 ON table_2.table_1_id = table_1.table_1_id
group by grouping sets((table_1.table_1_id, phone, name), (table_1.table_1_id, phone, name, some_data))
order by table_1.table_1_id, some_data nulls first;
┌────────────┬───────┬──────┬───────────┐
│ table_1_id │ phone │ name │ some_data │
╞════════════╪═══════╪══════╪═══════════╡
│          1 │ 502   │ aa   │ ░░░░      │
│       ░░░░ │ ░░░░  │ ░░░░ │ a         │
│       ░░░░ │ ░░░░  │ ░░░░ │ b         │
│       ░░░░ │ ░░░░  │ ░░░░ │ j         │
│       ░░░░ │ ░░░░  │ ░░░░ │ n         │
│          2 │ 268   │ bb   │ ░░░░      │
│       ░░░░ │ ░░░░  │ ░░░░ │ a         │
│       ░░░░ │ ░░░░  │ ░░░░ │ s         │
│       ░░░░ │ ░░░░  │ ░░░░ │ y         │
│          5 │ 984   │ ee   │ ░░░░      │
│       ░░░░ │ ░░░░  │ ░░░░ │ a         │
│       ░░░░ │ ░░░░  │ ░░░░ │ n         │
│       ░░░░ │ ░░░░  │ ░░░░ │ w         │
└────────────┴───────┴──────┴───────────┘

宾果!希望这是你要求的。