oracle 一旦我得到了某个列的所有表,我如何才能得到与该表相关的所有行?

ttygqcqt  于 2023-10-16  发布在  Oracle
关注(0)|答案(1)|浏览(107)

我有以下SQL for ORACLE(10 g)

select origTabCols.owner, origTabCols.table_name, 
(select COUNT(*) from all_tab_columns 
    where MARKET_ID = 1) as MarketCount
from all_tab_columns origTabCols
where origTabCols.column_name = 'MARKET_ID' 
group by origTabCols.owner, origTabCols.table_name
order by origTabCols.table_name asc;

此部分获取具有列MARKET_ID的所有表

select owner, table_name from all_tab_columns
where column_name = 'MARKET_ID' 
order by table_name;

但是现在,我需要列MARKET_ID = 1的表中的所有行以及每个结果集MARKET_ID = 1的行数。
结果应如下所示:

ID   |   OWNER       | TABLE_NAME      | ROWS_PER_TABLE
-----------------------------------------------------
1        DBA           TABLE_1           45
2        DBA           TABLE_2           452
3        DBA           TABLE_3           13
4        DBA           TABLE_4           95

进一步扩展,如果有一个子表的FOREIGN KEY,其中MARKET_ID = 1,我也需要知道这一点,以便执行CASCADING遍历
就像这样...

ID   |   OWNER       | TABLE_NAME      | ROWS_PER_TABLE    | FOREIGN_KEY | NUM_ROWS
------------------------------------------------------------------------------------
1        DBA           TABLE_1           45                  FK_ID_1         3
2        DBA           TABLE_2           452                 FK_ID_2         1556 
3        DBA           TABLE_3           13                  FK_ID_3         365   
4        DBA           TABLE_4           95                  FK_ID_4         22

谢谢你的帮助。

更新:

我实际上扩展了调用以反映PL/SQL中的解决方案
剩下的就是得到子表中的行的数量了.

set serveroutput on;

 

DECLARE
parent_table_name VARCHAR2(30) := 'AGREEMENT';
sql_stmt VARCHAR2(2000);
cursor_child_tables SYS_REFCURSOR;
child_table_name VARCHAR2(30);
column_name varchar(100);

 

BEGIN
  OPEN cursor_child_tables FOR
    SELECT C.table_name
    FROM all_constraints C
    JOIN all_cons_columns CC ON C.constraint_name = CC.constraint_name
    WHERE C.R_CONSTRAINT_NAME IN (
      SELECT CONSTRAINT_NAME from all_constraints WHERE table_name=parent_table_name
    ) 
    AND C.CONSTRAINT_TYPE = 'R';

LOOP
  FETCH cursor_child_tables INTO child_table_name;
  EXIT WHEN cursor_child_tables%NOTFOUND;

  sql_stmt := 'SELECT * FROM ' || child_table_name;
  DBMS_OUTPUT.PUT_LINE('Child_Table: ' || child_table_name);
  DECLARE
    cursor_columns SYS_REFCURSOR;
  BEGIN

    OPEN cursor_columns FOR
      SELECT column_name
      FROM all_tab_columns
      WHERE table_name = child_table_name;

      LOOP 
        FETCH cursor_columns INTO column_name;
        EXIT WHEN cursor_columns%NOTFOUND;
    END LOOP;

    CLOSE cursor_columns;
    END;

    END LOOP;
    CLOSE cursor_child_tables;
  END;

更新二:

所有,我们别无选择,只能使这与SQL工作.所以,我把它简化为三个步骤:
我想做的是把STEP 1作为一个循环插入到STEP 2中的ACCT_CODE中,然后当我找到子表时,我只需要继续循环TBL 1- 'TBL-....'并在输出中显示所有记录。
在DB中总共120个TABLES中,可能的PABLES表的总数不会超过31个。ACCT_CODE在本例中有4个CHILD表,TBL 1有1个ROW表。TBL 2-TBL 4可以是1 -“n”
我快到了

-- STEP 1
select owner, table_name from all_tab_columns
where column_name = 'MARKET_ID' 
order by table_name;

-- STEP 2
set serveroutput on;
DECLARE
parent_table_name VARCHAR2(30) := 'ACCT_CODE';

--CHILD TABLES for ACCT_CODE
--Child_Table: TBL1
--Child_Table: TBL2
--Child_Table: TBL3
--Child_Table: TBL4

sql_stmt VARCHAR2(2000);
cursor_child_tables SYS_REFCURSOR;
child_table_name VARCHAR2(30);
column_name varchar(100);

BEGIN
  OPEN cursor_child_tables FOR
    SELECT C.table_name
    FROM all_constraints C
    JOIN all_cons_columns CC ON C.constraint_name = CC.constraint_name
    WHERE C.R_CONSTRAINT_NAME IN (
      SELECT CONSTRAINT_NAME from all_constraints WHERE table_name=parent_table_name
    ) 
    AND C.CONSTRAINT_TYPE = 'R';

LOOP
  FETCH cursor_child_tables INTO child_table_name;
  EXIT WHEN cursor_child_tables%NOTFOUND;

  sql_stmt := 'SELECT * FROM ' || child_table_name;
  DBMS_OUTPUT.PUT_LINE('Child_Table: ' || child_table_name);
  DECLARE
    cursor_columns SYS_REFCURSOR;
  BEGIN

    OPEN cursor_columns FOR
      SELECT column_name
      FROM all_tab_columns
      WHERE table_name = child_table_name;

      LOOP 
        FETCH cursor_columns INTO column_name;
        EXIT WHEN cursor_columns%NOTFOUND;
    END LOOP;

    CLOSE cursor_columns;
    END;

    END LOOP;
    CLOSE cursor_child_tables;
  END;
  
  
  -- STEP 3
  select * from ACCT_CODE
  where MARKET_ID = 1;
des4xlb0

des4xlb01#

不确定,但我想你可以收集所有你需要的数据,除了MARKET_ID = 1的表中的行数。对于这一部分,你需要动态SQL,这意味着使用PL/SQL。无论如何,你可以从下面的代码中得到一些有用的东西。
首先是一些虚拟的样本数据:

Create Table T1_MARKETS(  MARKET_ID Number, MARKET_NAME VarChar2(32), PRIMARY KEY(MARKET_ID) );
Insert Into T1_MARKETS VALUES(1, 'EUROPE');
Insert Into T1_MARKETS VALUES(2, 'AMERICAS');
Commit;
--
Create Table T2_STATES(   STATE_ID Number, STATE_NAME VarChar2(32), MARKET_ID Number, PRIMARY KEY(STATE_ID),
                          FOREIGN KEY(MARKET_ID) REFERENCES T1_MARKETS(MARKET_ID) );
Insert Into T2_STATES VALUES(1, 'France', 1);
Insert Into T2_STATES VALUES(2, 'Germany', 1);
Insert Into T2_STATES VALUES(3, 'Croatia', 1);
Insert Into T2_STATES VALUES(4, 'Canada', 2);
Insert Into T2_STATES VALUES(5, 'Argentina', 2);
Commit;
--
Create Table T3_CITIES(   CITY_ID Number, CITY_NAME VarChar2(32), MARKET_ID Number, STATE_ID Number, PRIMARY KEY(CITY_ID),
                          FOREIGN KEY(MARKET_ID) REFERENCES T1_MARKETS(MARKET_ID),
                          FOREIGN KEY(STATE_ID) REFERENCES T2_STATES(STATE_ID) );
Insert Into T3_CITIES VALUES(1, 'Paris', 1, 1);
Insert Into T3_CITIES VALUES(2, 'Nantes', 1, 1);
Insert Into T3_CITIES VALUES(3, 'Berlin', 1, 2);
Insert Into T3_CITIES VALUES(4, 'Leipzig', 1, 2);
Insert Into T3_CITIES VALUES(5, 'Zagreb', 1, 3);
Insert Into T3_CITIES VALUES(6, 'Vancouver', 2, 4);
Insert Into T3_CITIES VALUES(7, 'Buenos Aires', 2, 5);
Commit;
--
Create Table T4_CUSTOMERS(CUSTOMER_ID Number, CUSTOMER_NAME VarChar2(32), MARKET_ID Number, STATE_ID Number, CITY_ID Number, PRIMARY KEY(CUSTOMER_ID),
                          FOREIGN KEY(MARKET_ID) REFERENCES T1_MARKETS(MARKET_ID),
                          FOREIGN KEY(STATE_ID) REFERENCES T2_STATES(STATE_ID),
                          FOREIGN KEY(CITY_ID) REFERENCES T3_CITIES(CITY_ID) );
Insert Into T4_CUSTOMERS VALUES(1, 'Sell it all inc FR', 1, 1, 1);
Insert Into T4_CUSTOMERS VALUES(2, 'Sell it all inc DE', 1, 2, 3);
Insert Into T4_CUSTOMERS VALUES(3, 'Sell it all inc HR', 1, 3, 5);
Insert Into T4_CUSTOMERS VALUES(4, 'Sell it all inc CA', 2, 4, 6);
Insert Into T4_CUSTOMERS VALUES(5, 'Sell it all inc AR', 2, 5, 7);
Commit;
--  -------------------------------------------------------------
--  Customers Data:
--
Select c.CUSTOMER_NAME, cty.CITY_NAME, s.STATE_NAME, m.MARKET_NAME
From T4_CUSTOMERS c
Inner Join T3_CITIES cty ON(cty.CITY_ID = c.CITY_ID)
Inner Join T2_STATES s ON(s.STATE_ID = c.STATE_ID)
Inner Join T1_MARKETS m on(m.MARKET_ID = c.MARKET_ID)
--
--  CUSTOMER_NAME            CITY_NAME      STATE_NAME     MARKET_NAME                     
--  -----------------------  -------------  -------------  -------------
--  Sell it all inc FR       Paris          France         EUROPE       
--  Sell it all inc DE       Berlin         Germany        EUROPE       
--  Sell it all inc HR       Zagreb         Croatia        EUROPE     
--  Sell it all inc CA       Vancouver      Canada         AMERICAS     
--  Sell it all inc AR       Buenos Aires   Argentina      AMERICAS  
--  ----------------------------------------------------------------------------------------------------------------------------
--

创建一个CTE(命名为网格),它将收集具有MARKET_ID列和与表关联的外键的表。

WITH
    grid AS
        (   Select      t.OWNER, t.TABLE_NAME "PK_TABLE", t.NUM_ROWS "PK_TABLE_ROWS", 
                        kc0.COLUMN_NAME "PK_COLUMN", kc0.CONSTRAINT_NAME "PK_NAME",
                        k1.TABLE_NAME "FK_TABLE", t1.NUM_ROWS "FK_TABLE_ROWS",
                        kc1.COLUMN_NAME "FK_COLUMN", kc1.CONSTRAINT_NAME "FK_NAME",
                        k1.R_CONSTRAINT_NAME "REFERENCED_PK_NAME"
            From        all_tables t 
            Inner Join  all_tab_columns c ON(c.OWNER = t.OWNER And c.TABLE_NAME = t.TABLE_NAME)
            Left Join   all_constraints k0 ON(k0.OWNER = t.OWNER And k0.TABLE_NAME = t.TABLE_NAME And k0.CONSTRAINT_TYPE = 'P')
            Left Join   all_cons_columns kc0 ON(kc0.OWNER = t.OWNER And kc0.CONSTRAINT_NAME = k0.CONSTRAINT_NAME)
            Left Join   all_constraints k1 ON(k1.OWNER = t.OWNER And k1.CONSTRAINT_TYPE = 'R' And k1.R_CONSTRAINT_NAME = k0.CONSTRAINT_NAME)
            Left Join   all_cons_columns kc1 ON(kc1.OWNER = k1.OWNER And kc1.CONSTRAINT_NAME = k1.CONSTRAINT_NAME)
            Left Join   all_tables t1 ON(t1.OWNER = k1.OWNER And t1.TABLE_NAME = k1.TABLE_NAME)
            Where       c.COLUMN_NAME = 'MARKET_ID' 
            Order By    t.TABLE_NAME
        )
/*
OWNER   PK_TABLE     PK_TABLE_ROWS  PK_COLUMN     PK_NAME       FK_TABLE        FK_TABLE_ROWS   FK_COLUMN   FK_NAME         REFERENCED_PK_NAME
------  ----------  --------------  ------------  ------------  -------------  --------------   ----------  --------------  ------------------
USER_1  T1_MARKETS              2   MARKET_ID     SYS_C0021837  T3_CITIES                   7   MARKET_ID   SYS_C0021841    SYS_C0021837
USER_1  T1_MARKETS              2   MARKET_ID     SYS_C0021837  T4_CUSTOMERS                5   MARKET_ID   SYS_C0021844    SYS_C0021837
USER_1  T1_MARKETS              2   MARKET_ID     SYS_C0021837  T2_STATES                   5   MARKET_ID   SYS_C0021839    SYS_C0021837
USER_1  T2_STATES               5   STATE_ID      SYS_C0021838  T4_CUSTOMERS                5   STATE_ID    SYS_C0021845    SYS_C0021838
USER_1  T2_STATES               5   STATE_ID      SYS_C0021838  T3_CITIES                   7   STATE_ID    SYS_C0021842    SYS_C0021838
USER_1  T3_CITIES               7   CITY_ID       SYS_C0021840  T4_CUSTOMERS                5   CITY_ID     SYS_C0021846    SYS_C0021840
USER_1  T4_CUSTOMERS            5   CUSTOMER_ID   SYS_C0021843                  
*/

有了这个结果,你就可以得到表格和它们的PK - FK关系。下面的代码为您提供了这些关系,并准备了与PL/SQL一起使用的动态SQL语句,以便您可以获得MARKET_ID = 1的行。

Select      OWNER "OWNER", 
            PK_TABLE "TABLE_NAME", 
            PK_TABLE_ROWS "TABLE_ROWS", 
            LISTAGG(Distinct FK_TABLE, ', ') WITHIN GROUP (Order By FK_TABLE) "REFERENCED_BY_TABLES",
            LISTAGG(Distinct FK_NAME, ', ') WITHIN GROUP (Order By FK_TABLE) "REFERENCED_BY_FK_NAMES",
            LISTAGG(Distinct Case When PK_COLUMN = 'MARKET_ID' Then FK_TABLE End, ', ') WITHIN GROUP (Order By FK_TABLE) "REFERENCED_BY_TABLES_VIA_MARKET_ID",
            'Select Count(*) "ROWS_WHERE_MARKET_ID_IS_1" From ' || PK_TABLE || ' Where MARKET_ID = 1' "SQL_TABLE_MARKET_ID_1_ROWS"
From        grid
Where       Nvl(REFERENCED_PK_NAME, PK_NAME) = PK_NAME
Group By    OWNER, PK_TABLE, PK_TABLE_ROWS, Nvl(REFERENCED_PK_NAME, PK_NAME)
Order By    PK_TABLE
/*
OWNER   TABLE_NAME     TABLE_ROWS   REFERENCED_BY_TABLES                 REFERENCED_BY_FK_NAMES                     REFERENCED_BY_TABLES_VIA_MARKET_ID  SQL_TABLE_MARKET_ID_1_ROWS
------  ------------  -----------   ----------------------------------  ------------------------------------------  ----------------------------------  ---------------------------------------------------------------------------------
USER_1  T1_MARKETS              2   T2_STATES, T3_CITIES, T4_CUSTOMERS  SYS_C0021839, SYS_C0021841, SYS_C0021844    T2_STATES, T3_CITIES, T4_CUSTOMERS  Select Count(*) "ROWS_WHERE_MARKET_ID_IS_1" From T1_MARKETS Where MARKET_ID = 1
USER_1  T2_STATES               5   T3_CITIES, T4_CUSTOMERS             SYS_C0021842, SYS_C0021845                  null                                Select Count(*) "ROWS_WHERE_MARKET_ID_IS_1" From T2_STATES Where MARKET_ID = 1
USER_1  T3_CITIES               7   T4_CUSTOMERS                        SYS_C0021846                                null                                Select Count(*) "ROWS_WHERE_MARKET_ID_IS_1" From T3_CITIES Where MARKET_ID = 1
USER_1  T4_CUSTOMERS            5   NULL                                null                                        null                                Select Count(*) "ROWS_WHERE_MARKET_ID_IS_1" From T4_CUSTOMERS Where MARKET_ID = 1
*/

LISTAGG(Distinct...)可能不适用于10 g-它在这里只是描述互连,你不需要它。
PL/SQL代码,Cursor声明自上述代码。

SET SERVEROUTPUT ON
Declare
    CURSOR c IS
       WITH
          grid AS
                ... code from above ...;
    cSet c%ROWTYPE;
    Counter Number := 0;
    NumRows Number := 0;
    DataRow VarChar2(80);
Begin
    DBMS_OUTPUT.PUT_LINE('ID' || '  ' || RPAD('OWNER', 12, ' ') || '  TABLE_NAME      ROWS_PER_TABLE  NUM_ROWS_1');
    DBMS_OUTPUT.PUT_LINE('--  ------------  --------------  --------------  ----------');
    OPEN c;
    LOOP
        FETCH c InTo cSet;
        EXIT WHEN c%NOTFOUND;
        Counter := Counter + 1;
        DataRow := '';
        Execute Immediate cSet.SQL_PK_TABLE_MARKET_ID_1_ROWS Into NumRows;
        DataRow := DataRow || LPad(Counter, 3 - Length(Counter), ' ') || LPAD('  ', 3 - Length(Counter), ' ');
        DataRow := DataRow || cSet.OWNER || LPAD('  ', 14 - Length(cSet.OWNER), ' ');
        DataRow := DataRow || cSet."TABLE" || LPAD('  ', 14 - Length(cSet."TABLE"), ' ');
        DataRow := DataRow || LPad(cSet.TABLE_ROWS, 17 - Length(cSet.TABLE_ROWS), ' ');
        DataRow := DataRow || LPad(NumRows, 13 - Length(NumRows), ' ');
        DBMS_OUTPUT.PUT_LINE(DataRow);
    END LOOP;
    CLOSE c;
End;
/
--
--  R e s u l t :
--
--  ID  OWNER         TABLE_NAME      ROWS_PER_TABLE  NUM_ROWS_1
--  --  ------------  --------------  --------------  ----------
--   1  USER_1        T1_MARKETS                   2           1
--   2  USER_1        T2_STATES                    5           3
--   3  USER_1        T3_CITIES                    7           5
--   4  USER_1        T4_CUSTOMERS                 5           3
--  
--  PL/SQL procedure successfully completed.

NUM_ROWS_1列是MARKET_ID = 1的每个表的行数
希望你能根据你的实际情况调整一下。

相关问题