Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/84.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
这可以在SQL而不是循环中完成吗?_Sql_Oracle_Plsql_Common Table Expression - Fatal编程技术网

这可以在SQL而不是循环中完成吗?

这可以在SQL而不是循环中完成吗?,sql,oracle,plsql,common-table-expression,Sql,Oracle,Plsql,Common Table Expression,我有几个表,希望从另一个表中更新一个表: create table first_table (bookstore_id number not null, event varchar2(10), timestamp date); create table second_table (bookstore_id number, numbooks number); insert into second_table values (1,0); insert into second_tab

我有几个表,希望从另一个表中更新一个表:

create table first_table
(bookstore_id number not null,
event   varchar2(10),
timestamp   date);

create table second_table
(bookstore_id number,
numbooks    number);

insert into second_table values (1,0);
insert into second_table values (2,0);
insert into second_table values (3,0);

insert into first_table values (1, 'ADD', sysdate);
insert into first_table values (1, 'ADD', sysdate);
insert into first_table values (1, 'ADD', sysdate);
insert into first_table values (1, 'REMOVE', sysdate);
insert into first_table values (1, 'ADD', sysdate);
insert into first_table values (1, 'REMOVE', sysdate);
insert into first_table values (2, 'ADD', sysdate);
insert into first_table values (2, 'ADD', sysdate);
insert into first_table values (2, 'REMOVE', sysdate);
insert into first_table values (2, 'ADD', sysdate);
insert into first_table values (2, 'ADD', sysdate);
insert into first_table values (2, 'ADD', sysdate);
insert into first_table values (3, 'ADD', sysdate);
insert into first_table values (3, 'ADD', sysdate);
insert into first_table values (3, 'REMOVE', sysdate);
insert into first_table values (3, 'ADD', sysdate);
insert into first_table values (3, 'REMOVE', sysdate);
insert into first_table values (3, 'ADD', sysdate);
insert into first_table values (3, 'REMOVE', sysdate);
以下逻辑将用于执行我想要的操作:

begin
    for storeid in (select bookstore_id from second_table)
    loop
        update second_table
        set numbooks =
            (select count(*) from first_table
            where event = 'ADD'
            and bookstore_id = storeid.bookstore_id)
            -   /* actual minus sign is needed here */
            (select count(*) from first_table
            where event = 'REMOVE'
            and bookstore_id = storeid.bookstore_id)
        where bookstore_id = storeid.bookstore_id;
    end loop;
end;
/

我的问题是,是否可以使用单个SQL语句来避免循环?

不需要CTE或其他任何东西,您可以这样做:

update second_table
set numbooks =
              ((select count(*) from first_table
               where event = 'ADD'
               and bookstore_id = second_table.bookstore_id)
               -   /* actual minus sign is needed here */
               (select count(*) from first_table
                where event = 'REMOVE'
                and bookstore_id = second_table.bookstore_id))
它实际上可以通过条件聚合完成,并避免从第一个表中选择1项:

update second_table
set numbooks =
              (select (count(CASE WHEN event = 'ADD' then 1 end)
                       -
                       count(CASE WHEN event = 'REMOVE' then 1 end))
               from first_table
               WHERE bookstore_id = second_table.bookstore_id)
 WHERE EXISTS(select 1 from first_table s where second_table.bookstore_id = s.bookstore_id)

不需要CTE或任何东西,您可以这样做:

update second_table
set numbooks =
              ((select count(*) from first_table
               where event = 'ADD'
               and bookstore_id = second_table.bookstore_id)
               -   /* actual minus sign is needed here */
               (select count(*) from first_table
                where event = 'REMOVE'
                and bookstore_id = second_table.bookstore_id))
它实际上可以通过条件聚合完成,并避免从第一个表中选择1项:

update second_table
set numbooks =
              (select (count(CASE WHEN event = 'ADD' then 1 end)
                       -
                       count(CASE WHEN event = 'REMOVE' then 1 end))
               from first_table
               WHERE bookstore_id = second_table.bookstore_id)
 WHERE EXISTS(select 1 from first_table s where second_table.bookstore_id = s.bookstore_id)

您可以直接在SQL中执行此操作。以下是Oracle中的一种方法,其他数据库具有更简单的机制:

update second_table st
     set numbooks = (select sum(case when event = 'ADD' then 1
                                     when event = 'REMOVE' then -1
                                     else 0
                                end)
                     from first_table ft
                     where st.bookstore_id = ft.bookstore_id
                    )
     where exists (select 1 from first_table where st.bookstore_id = ft.bookstore_id);
请注意,where子句仅更新第二个表中第一个表中的行。如果您知道所有的行都在那里,或者如果您想用NULL更新缺少的行,可以很容易地将其更改为0,那么就不要包含它


如果有许多行是其他类型的事件,那么子查询中“添加”、“删除”中的where event可能会提高性能。

您可以直接在SQL中执行此操作。以下是Oracle中的一种方法,其他数据库具有更简单的机制:

update second_table st
     set numbooks = (select sum(case when event = 'ADD' then 1
                                     when event = 'REMOVE' then -1
                                     else 0
                                end)
                     from first_table ft
                     where st.bookstore_id = ft.bookstore_id
                    )
     where exists (select 1 from first_table where st.bookstore_id = ft.bookstore_id);
请注意,where子句仅更新第二个表中第一个表中的行。如果您知道所有的行都在那里,或者如果您想用NULL更新缺少的行,可以很容易地将其更改为0,那么就不要包含它


如果有许多行是其他类型的事件,那么子查询中“添加”、“删除”中的where event可能会提高性能。

一般来说,不希望存储可以计算的数据。第二个表可以很容易地实现为一个视图:选择bookstore\u id,SUMCASE WHEN event='ADD',然后按bookstore\u id从第一个表组中选择1 ELSE-1作为num\u books结束。如果性能有问题,可能有办法让您的DBMS自动持久化此视图中的数据Oracle:Materialized Views,SQL Server:索引视图。这是一个更复杂问题的简化示例,但逻辑类似。我的问题是我是否可以避免使用循环和plsql来做这种事情。你可以避免循环,这并不难做到。但是,你绝对应该听从建议,不要存储那些可以从现有数据中计算出来的数据。一般来说,最好不要存储那些可以计算出来的数据。第二个表可以很容易地实现为一个视图:选择bookstore\u id,SUMCASE WHEN event='ADD',然后按bookstore\u id从第一个表组中选择1 ELSE-1作为num\u books结束。如果性能有问题,可能有办法让您的DBMS自动持久化此视图中的数据Oracle:Materialized Views,SQL Server:索引视图。这是一个更复杂问题的简化示例,但逻辑类似。我的问题是我是否可以避免使用循环和plsql来做这种事情。你可以避免循环,这并不难做到。但是,您绝对应该听取建议,而不是存储可以从现有数据中轻松计算出来的数据。