搜索多个表,并在结果行中显示表名

时间:2014-03-18 09:33:00

标签: sql postgresql database-design dynamic-sql

如何构造SQL语句以跨多个不相关的平面表运行,并显示结果以及结果来自的表的结果和表的名称。

这个场景是我有几个表,每个表都有相同的列名。我收集的是外部各方提供的数据,因为它存放在不同的表格中。

相同的表格如下:

Table 1: pid, parent_name, student_name, student_number, class_name, columnN
Table 2: pid, previous_school, previous_school, student_number, columnN
Table 3: pid, student_name, student_number, parent_name, column4, columnN
Table 14: pid, student_number, parent_name, column4, columnN
Table N: pid, previous_school, parent_name, column4, columnN

我需要一个在所有表中搜索student_name的SQL语句 在伪代码中:for each table, find a student named john doe and return to me the row where you got the result and the table where you found the result

在以下演示文稿中给出结果:

john doe, Table 1, pid
john doe, Table 9, pid

为了使它有点复杂,列student_name可能不在所有表中,因此如果在那里找不到列,查询需要慷慨地进行。

3 个答案:

答案 0 :(得分:5)

您正在寻找动态SQL。自动从系统目录中汇编查询:

SELECT string_agg('SELECT student_name, '''
                   || c.oid::regclass || ''' AS tbl, pid FROM '
                   || c.oid::regclass
                   || $$ WHERE student_name = 'John Doe'$$
                 , E'\nUNION ALL\n')
FROM   pg_namespace n
JOIN   pg_class     c ON c.relnamespace = n.oid
WHERE  n.nspname = 'public'         -- schema name where your tables lie
AND    c.relname LIKE 't%'          -- and / or filter table names
AND    EXISTS (
   SELECT 1 FROM pg_attribute 
   WHERE  attrelid = c.oid
   AND    attname = 'student_name'  -- make sure column exists
   AND    NOT attisdropped          -- and is alive
   );

生成查询字符串:

SELECT student_name, 'tbl1' AS tbl, pid FROM tbl1 WHERE student_name = 'John Doe'
UNION ALL
SELECT student_name, 'tbl2' AS tbl, pid FROM tbl2 WHERE student_name = 'John Doe'
UNION ALL
SELECT student_name, 'tbl3' AS tbl, pid FROM tbl3 WHERE student_name = 'John Doe'
...

然后在第二次调用中运行它或使用EXECUTE使用PL / pgSQL函数完全自动化它。例如:
Select a dynamic set of columns from a table and get the sum for each

此查询生成safe code with sanitized identifiers preventing SQL injection.(此处为oid::regclass的说明。)

还有更多相关答案。 Use a search.

BTW,LIKE中的student_name LIKE 'John Doe'毫无意义。如果没有通配符,只需使用=

答案 1 :(得分:0)

只需为描述源表的每个选择添加一个文字值:

select student_name, 'Table 1', pid
from table1
where ...
union
select some_name, 'Table 2', pid
from table2
where ...
union
...

答案 2 :(得分:0)

您可以从all_tables视图中获取表的名称,以dinamically方式创建union查询,然后使用execute immediate执行它。这样的事情 - 小心代码可能有错误 - :

DECLARE
  v_query VARCHAR2(4000) := '';
  v_student_name VARCHAR2(50) := 'John Doe';

  type r_results is record (
    student_name VARCHAR2(500),
    table_name VARCHAR2(100),
    pid NUMBER
  );

  v_results r_results;

  CURSOR c_tables IS
    SELECT table_name 
    FROM all_tables 
    WHERE upper(table_name) LIKE '%_STUDENT_RECORDS';
BEGIN      
  FOR client_table IN c_tables LOOP
    IF v_query IS NOT NULL THEN
      v_query := v_query || ' UNION ';
    END IF;

    v_query := v_query || 'SELECT student_name, ' || client_table.table_name || ', ' || pid FROM ' || client_table.table_name || ' WHERE student_name = ''' || v_student_name || '''';
  END LOOP;


  EXECUTE IMMEDIATE v_query INTO v_results;
END;