Изтриване от една таблица и актуализиране на друга

Имам две таблици със следните колони:

SUMMARY(sum_id, sum_number) and DETAILS(det_id, det_number, sum_id)

Искам да изтрия редове от таблица DETAILS с det_id в списъка с идентификатори, което може да стане чрез:

DELETE FROM details WHERE det_id in (1,2,3...)

НО

  1. В същото време трябва да актуализирам таблица SUMMARY, ако summary.sum_id=details.sum_id

    UPDATE summary SET sum_number-=somefunction(details.det_number) 
    WHERE summary.sum_id=details.sum_id
    
  2. Нещо повече, след това би било напълно чудесно да изтриете редове от SUMMARY таблица, ако sum_number<=0

Как да направите всичко това по интелигентен начин?

Ами ако знам от самото начало и двата идентификатора: details.det_id (за изтриване) И summary.sum_id, които съответстват на details.det_id


person Stan    schedule 18.09.2012    source източник
comment
Какъв SQL двигател/диалект използвате - MySQL, MS SQL, PostgreSQL? Поддържа ли транзакции, тригери, съхранени процедури и т.н.?   -  person Artemix    schedule 18.09.2012
comment
бих предпочел да избягвам нещо като тригери или съхранени процедури   -  person Stan    schedule 18.09.2012
comment
Тъй като не искате да използвате никакви SQL разширения, най-добрият начин е да изпълните тези три операции стъпка по стъпка. В този случай най-интелигентният начин е да ги извършите в една транзакция.   -  person Artemix    schedule 18.09.2012


Отговори (3)


Не сте посочили СУБД, така че предполагам PostgreSQL.

Можете да направите това с един оператор, като използвате новата функция за CTE за запис:

with deleted as (
   delete from details
   where det_id in (1,2,3...)
   returning details.*
),
new_summary as (
   update summary 
      set sum_number = some_function(deleted.det_number)
   from deleted
   where delete.sum_id = summary.sum_id
   returning summary.sum_id
) 
delete from summary 
where sum_number <= 0
and sum_id in (select sum_id from new_summary);

Условието in във външното изтриване не е строго необходимо, но може да нямате CTE дефиниции, които не използвате, така че условието гарантира, че new_summary CTE действително се използва в израза. Освен това може малко да подобри производителността, тъй като се проверяват само променените обобщени редове (не всички).

person a_horse_with_no_name    schedule 18.09.2012
comment

Кажете ми защо пейджингът спря да работи. По-скоро странирането работи, но дава 404 страница.

Пример: altyncev.ru/posts

Конфигурация и файл с публикации в моето репо.

Глобални промени не се правят.

Публикации:

<% posts = @getCollection('posts') %>
<% for i in [@[email protected]]: %>
    <% document = posts.at(i).toJSON() %>
    <article class="post">
        <p class="posts_date"><%= @formatDate(document.date) %></p>
        <a href="/bg<%= document.url %>"><h3><%= document.title %></h3></a>
        <div class="post-content"><%- @getCuttedContent(String(document.contentRenderedWithoutLayouts)) %></div>
        <% if @hasReadMore(String(document.contentRenderedWithoutLayouts)): %>
        <div class="read_more"><a href="/bg<%= document.url %>"><strong>Читать далее &rarr;</strong></a></div>
        <% end %>
    </article>
<% end %>

<div class="pagination">
    <ul>
        <% if !@getDocument().hasPrevPage(): %>
            <li class="disabled"><span>«</span></li>
        <% else: %>
            <li><a href="/bg<%= @getDocument().getPrevPage() %>">«</a></li>
        <% end %>
        <% for num in [[email protected]]: %>
            <% if @document.page.number == num: %>
                <li class="active"><span><%= num %></span></li>
            <% else: %>
                <li><a href="/bg<%= @getDocument().getPagedUrl(num) %>"><%= num %></a></li>
            <% end %>
        <% end %>
        <% if !@getDocument().hasNextPage(): %>
            <li class="disabled"><span>»</span></li>
        <% else: %>
            <li><a href="/bg<%= @getDocument().getNextPage() %>">»</a></li>
        <% end %>
    </ul>
</div>
- person Stan; 18.09.2012
comment
@Stan: правенето му независим от СУБД просто означава, че ще работи еднакво бавно/зле на всички двигатели. Трябва да обмислите специфични за СУБД решения за всичко, което е по-сложно от select * from foo. - person a_horse_with_no_name; 18.09.2012

Не е възможно да се извършат всички тези операции в един оператор. Ще трябва да направите нещо подобно:

UPDATE summary SET sum_number = somefunction(details.det_number)
FROM summary INNER JOIN details ON summary.sum_id = details.sum_id

DELETE FROM details WHERE det_id IN (1,2,3,...)

DELETE FROM summary WHERE sum_number <= 0
person Dan    schedule 18.09.2012
comment
Как можеш да си толкова сигурен, че няма и други начини? - person askmish; 18.09.2012
comment
Ако приемем, че OP използва диалекта T-SQL, няма начин (поне доколкото ми е известно) да изтриете от две таблици наведнъж, като използвате само един оператор. Може би чрез някакво подходящо използване на изгледи това по принцип може да бъде постигнато, но мисля, че това донякъде противоречи на смисъла да се прави по интелигентен начин. - person Dan; 18.09.2012

Бих използвал тригер... тогава базата данни е отговорна за изтриванията.

Използването на тригер за актуализиране, веднъж/ако актуализацията е успешна, ако ще задейства тригера, който може да направи толкова или толкова малко, колкото ви е необходимо... т.е. може да направи вашите 2 изтривания.

За пример прочетете този урок:

http://www.mysqltutorial.org/create-the-first-trigger-in-mysql.aspx този отговор (http://stackoverflow.com/questions/6296313/mysql-trigger-after-update-only-if-row-has-changed) от stackoverflow също предоставя добър пример.

person Brian    schedule 18.09.2012