如何使用PL / SQL函数比较两个表?

时间:2013-09-05 10:31:27

标签: function plsql

我是plsql的新手并且正在努力编写代码。我想使用plsql函数比较两个表,(除了记录之外,两个表完全相同)。输入参数将是(table1,table2) - 它应该比较table1和table2并返回三个输出。

  1. 表之间的任何不匹配记录
  2. table1中存在的任何行,在table2中不存在。
  3. table2中存在且table1中不存在的任何行。
  4. 我在SQL中编写了查询但它有效,但我在这里硬编码了一个特定的表名。 请告知如何转换为函数。

    SET TERMOUT OFF CONCAT OFF VERIFY OFF
    SET FEEDBACK OFF
    SET MARKUP HTML ON SPOOL ON
    SPOOL ACTION.HTML
    set pages 1000 lines 125
    
    ----
    PROMPT SHOWING THE DIFFERENCE WITH THE MATCHING RECORDS FOR TABLE ACTION
    BREAK ON ACTIONID  duplicates skip page
    column tblname format a10
    select ACTIONID,tblname "tblname",ACTIONDESC,ACTIONNAME
    from ((SELECT 'OLD VALUES' tblname,ACTIONID,ACTIONDESC,ACTIONNAME
    FROM 'DEPL_ACTION
    MINUS
    SELECT 'NEW VALUES'  tblname,ACTIONID,ACTIONDESC,ACTIONNAME
    FROM ACTION )
    UNION ALL
    ( SELECT 'NEW VALUES'  tblname,ACTIONID,ACTIONDESC,ACTIONNAME
    FROM ACTION
    MINUS
    SELECT 'OLD VALUES' tblname,ACTIONID,ACTIONDESC,ACTIONNAME
    FROM 'DEPL_ACTION )) aa  where (ACTIONID) in ( select ACTIONID from (
    (SELECT ACTIONID,ACTIONDESC,ACTIONNAME
    FROM 'DEPL_ACTION
    MINUS
    SELECT ACTIONID,ACTIONDESC,ACTIONNAME
    FROM ACTION )
    UNION ALL
    ( SELECT ACTIONID,ACTIONDESC,ACTIONNAME
    FROM ACTION
    MINUS
    SELECT ACTIONID,ACTIONDESC,ACTIONNAME
    FROM 'DEPL_ACTION ) )  group by ACTIONID having count(*) > 1 ) order by ACTIONID;
    CLEAR BREAKS
    
    PROMPT SHOWING THE EXTRA RECORDS IN OLD VALUES FOR TABLE ACTION
    select ACTIONID,tblname "tblname",ACTIONDESC,ACTIONNAME
    from ((SELECT 'OLD VALUES' tblname,ACTIONID,ACTIONDESC,ACTIONNAME
    FROM 'DEPL_ACTION
    MINUS
    SELECT 'NEW VALUES'  tblname,ACTIONID,ACTIONDESC,ACTIONNAME
    FROM ACTION )
    UNION ALL
    ( SELECT 'NEW VALUES'  tblname,ACTIONID,ACTIONDESC,ACTIONNAME
    FROM ACTION
    MINUS
    SELECT 'OLD VALUES' tblname,ACTIONID,ACTIONDESC,ACTIONNAME
    FROM 'DEPL_ACTION )) aa  where (ACTIONID) in ( select ACTIONID from (
    (SELECT ACTIONID,ACTIONDESC,ACTIONNAME
    FROM 'DEPL_ACTION
    MINUS
    SELECT ACTIONID,ACTIONDESC,ACTIONNAME
    FROM ACTION )
    UNION ALL
    ( SELECT ACTIONID,ACTIONDESC,ACTIONNAME
    FROM ACTION
    MINUS
    SELECT ACTIONID,ACTIONDESC,ACTIONNAME
    FROM 'DEPL_ACTION ) )  group by ACTIONID having count(*) = 1 )  order by ACTIONID;
    
    PROMPT SHOWING THE EXTRA RECORDS IN NEW VALUES FOR TABLE ACTION
    select ACTIONID,tblname "tblname",ACTIONDESC,ACTIONNAME
    from ((SELECT 'OLD VALUES' tblname,ACTIONID,ACTIONDESC,ACTIONNAME
    FROM 'DEPL_ACTION
    MINUS
    SELECT 'NEW VALUES'  tblname,ACTIONID,ACTIONDESC,ACTIONNAME
    FROM ACTION )
    UNION ALL
    ( SELECT 'NEW VALUES'  tblname,ACTIONID,ACTIONDESC,ACTIONNAME
    FROM ACTION
    MINUS
    SELECT 'OLD VALUES' tblname,ACTIONID,ACTIONDESC,ACTIONNAME
    FROM 'DEPL_ACTION )) aa  where (ACTIONID) in ( select ACTIONID from (
    (SELECT ACTIONID,ACTIONDESC,ACTIONNAME
    FROM 'DEPL_ACTION
    MINUS
    SELECT ACTIONID,ACTIONDESC,ACTIONNAME
    FROM ACTION )
    UNION ALL
    ( SELECT ACTIONID,ACTIONDESC,ACTIONNAME
    FROM ACTION
    MINUS
    SELECT ACTIONID,ACTIONDESC,ACTIONNAME
    FROM 'DEPL_ACTION ) )  group by ACTIONID having count(*) = 1 ) order by ACTIONID;
    
    
    
    SET MARKUP HTML OFF
    SPOOL OFF
    EXIT
    

2 个答案:

答案 0 :(得分:0)

我不会为它创建一个终极功能,维护它将非常困难。每个表格创建一个包。

部首:

CREATE OR REPLACE PACKAGE tab_a_pkg AS

    TYPE tab_a_ntt IS TABLE OF tab_a%ROWTYPE;

    FUNCTION mismatched RETURN tab_a_ntt;

    FUNCTION a_minus_b RETURN tab_a_ntt;

    FUNCTION b_minus_a RETURN tab_a_ntt;

END tab_a_pkg;

体:

CREATE OR REPLACE PACKAGE BODY tab_a_pkg AS

    FUNCTION mismatched RETURN tab_a_ntt
    AS
        l_return  tab_a_ntt;
    BEGIN
        SELECT  NVL(col_a1, col_b1) AS col_1
        ,       NVL(col_a2, col_b2) AS col_2
        BULK    COLLECT INTO l_return
        FROM    tab_a
        FULL    JOIN tab_b
        ON      col_a1 = col_b1
        AND     col_a2 = col_b2
        WHERE   col_a1 IS NULL
        OR      col_b1 IS NULL;

        RETURN l_return;
    END mismatched;



    FUNCTION a_minus_b RETURN tab_a_ntt
    AS
        l_return  tab_a_ntt;
    BEGIN
        SELECT  *
        BULK    COLLECT INTO l_return
        FROM
        (
            SELECT * FROM tab_a
            MINUS
            SELECT * FROM tab_b
        );

        RETURN l_return;
    END a_minus_b;



    FUNCTION b_minus_a RETURN tab_a_ntt
    AS
        l_return  tab_a_ntt;
    BEGIN
        SELECT  *
        BULK    COLLECT INTO l_return
        FROM
        (
            SELECT * FROM tab_b
            MINUS
            SELECT * FROM tab_a
        );

        RETURN l_return;
    END b_minus_a;

END tab_a_pkg;

执行命令

DECLARE
    l_tab_a  tab_a_pkg.tab_a_ntt;
BEGIN
    l_tab_a := tab_a_pkg.mismatched();

    FOR indx IN 1..l_tab_a.COUNT LOOP
        DBMS_OUTPUT.PUT_LINE(l_tab_a(indx).col_a1 || ' ' || l_tab_a(indx).col_a2);
    END LOOP;
    DBMS_OUTPUT.PUT_LINE('------');


    l_tab_a := tab_a_pkg.a_minus_b();

    FOR indx IN 1..l_tab_a.COUNT LOOP
        DBMS_OUTPUT.PUT_LINE(l_tab_a(indx).col_a1 || ' ' || l_tab_a(indx).col_a2);
    END LOOP;
    DBMS_OUTPUT.PUT_LINE('------');


    l_tab_a := tab_a_pkg.b_minus_a();

    FOR indx IN 1..l_tab_a.COUNT LOOP
        DBMS_OUTPUT.PUT_LINE(l_tab_a(indx).col_a1 || ' ' || l_tab_a(indx).col_a2);
    END LOOP;
    DBMS_OUTPUT.PUT_LINE('------');
END;
/*
23 223
24 224
13 123
14 124
------
13 123
14 124
------
23 223
24 224
------
*/

答案 1 :(得分:0)

这个proc商店也许就像你搜索一样 我把它发布到这个网站的另一个主题,但我不记得是哪一个:)

用于比较具有相同pk的2个表中的选定字段 ps_TableGap'tbl1','tbl2','fld1,fld2,fld3 ... tbl1','Fld4,fld5,fld6 ...的字段tbl2的字段(可选我们为tbl1为空)'

你有3个结果基于tbl1'DEL','ADD','GAP' tbl2的字段以_为前缀为不同的(需要有不同的字段名称来推送结果报告服务)

/****** Object:  StoredProcedure [dbo].[ps_TableGap]    Script Date: 10/03/2013 16:03:44 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

-- =============================================
-- Author:       Arnaud ALLAVENA
-- Create date: 03.10.2013
-- Description: Compare tables
-- =============================================
alter PROCEDURE [dbo].[ps_TableGap]
    -- Add the parameters for the stored procedure here
    @Tbl1 as varchar(100),@Tbl2 as varchar(100),@Fld1 as varchar(1000), @Fld2 as varchar(1000)= ''
AS
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.

    SET NOCOUNT ON;
--Variables
--@Tbl1 = table 1
--@Tbl2 = table 2
--@Fld1 = Fields to compare from table 1
--@Fld2 Fields to compare from table 2
Declare @SQL varchar(8000)= '' --SQL statements
Declare @nLoop int = 1 --loop counter
Declare @Pk varchar(1000)= '' --primary key(s) 
Declare @Pk1 varchar(1000)= '' --first field of primary key
declare @strTmp varchar(50) = '' --returns value in Pk determination
declare @FldTmp varchar (1000) = '' --temporarily fields for alias calculation

--If @Fld2 empty we take @Fld1
--fields rules: fields to be compare must be in same order and type - always returns Gap
If @Fld2 = '' Set @Fld2 = @Fld1

--Change @Fld2 with Alias prefix xxx become _xxx 
while charindex(',',@Fld2)>0
begin
    Set @FldTmp = @FldTmp + (select substring(@Fld2,1,charindex(',',@Fld2)-1) + ' as _' + substring(@Fld2,1,charindex(',',@Fld2)-1) + ',')
    Set @Fld2 = (select ltrim(right(@Fld2,len(@Fld2)-charindex(',',@Fld2))))
end
Set @FldTmp = @FldTmp + @Fld2 + ' as _' + @Fld2
Set @Fld2 = @FldTmp

--Determinate primary key jointure
--rule: same pk in both tables
Set @nLoop = 1
Set @SQL = 'Declare crsr cursor for select COLUMN_NAME from INFORMATION_SCHEMA.KEY_COLUMN_USAGE where TABLE_NAME = '''
 + @Tbl1 + ''' or TABLE_SCHEMA + ''.'' + TABLE_NAME = ''' + @Tbl1 +  ''' or TABLE_CATALOG + ''.'' + TABLE_SCHEMA + ''.'' + TABLE_NAME = ''' + @Tbl1 
 + ''' order by ORDINAL_POSITION'
exec(@SQL)
open crsr 
fetch next from crsr into @strTmp
while @@fetch_status = 0
begin 
    if @nLoop = 1 
    begin 
        Set @Pk = 's.' + @strTmp + ' = b._' + @strTmp
        Set @Pk1 = @strTmp
        set @nLoop = @nLoop + 1 
    end 
    Else
    Set @Pk = @Pk + ' and s.' + @strTmp + ' = b._' + @strTmp
fetch next from crsr into @strTmp 

end 
close crsr
deallocate crsr

--SQL statement build
set @SQL = 'select case when s.' + @Pk1 + ' is null then ''Del'' when b._' + @Pk1 + ' is null then ''Add'' else ''Gap'' end as TypErr, '''
set @SQL = @SQL + @Tbl1 +''' as Tbl1, s.*, ''' + @Tbl2 +''' as Tbl2 ,b.* from (Select ' + @Fld1 + ' from ' + @Tbl1
set @SQL = @SQL + ' EXCEPT SELECT ' + @Fld2 + ' from ' + @Tbl2 + ')s full join (Select ' + @Fld2 + ' from ' + @Tbl2 
set @SQL = @SQL + ' EXCEPT SELECT ' + @Fld1 + ' from ' + @Tbl1 +')b on '+ @Pk 

--Run SQL statement
Exec(@SQL)
END