[PostgreSQL] - trigger/funkcja dla wybranych wierszy

[PostgreSQL] - trigger/funkcja dla wybranych wierszy
L8
  • Rejestracja:około 8 lat
  • Ostatnio:prawie 6 lat
  • Postów:99
0

Hej,

Potrzebuję utworzyć parę trigger/funkcja, która spowoduje to, że w momencie zmiany jednej wartości jednej kolumny, w innej zapisze się wynik pewnego działania. Na ten moment dotarłem do miejsca, gdzie jeśli zmienię jedną wartość tej kolumny, to cała inna kolumna zostaje zmieniona.

Trigger:

Kopiuj
CREATE TRIGGER update_day
AFTER UPDATE
ON test
FOR EACH ROW
EXECUTE update_days();

Funkcja:

Kopiuj
CREATE OR REPLACE FUNCTION update_days()
RETURNS trigger AS
$BODY$
BEGIN
IF NEW.start_date <> OLD.start_date THEN
UPDATE test SET days=end_date::date - new.start_date::date;
ELSEIF NEW.end_date <> OLD.end_date THEN
UPDATE test SET days=new.end_date::date - start_date::date;
END IF;

RETURN NEW;
END
$BODY$

LANGUAGE plpgsql

I teraz jak zrobię:

Kopiuj
UPDATE test SET start_date='2019-01-01' WHERE id=1;

To w tym momencie kolumna days zostaje w całości nadpisana nowymi wyliczonymi wartościami. A docelowo chodzi o to, aby tylko jeden rekord został zmodyfikowany (z id=1).

Marcin.Miga
Nigdzie NULLi nie sprawdzasz?
L8
To jest tylko na potrzeby hobbystyczne, nie idzie na produkcję póki co :)
YA
  • Rejestracja:prawie 10 lat
  • Ostatnio:około 15 godzin
  • Postów:2368
0

Przecież w definicji robisz updatea na całej tabeli, to co się dziwisz :)

Pewni chodzi Ci o zmodyfikowanie bieżącej wartości wiersza, tj. zamiast update:

Kopiuj
new.days=new.end_date::date - start_date::date;
L8
  • Rejestracja:około 8 lat
  • Ostatnio:prawie 6 lat
  • Postów:99
0
yarel napisał(a):

Przecież w definicji robisz updatea na całej tabeli, to co się dziwisz :)

Pewni chodzi Ci o zmodyfikowanie bieżącej wartości wiersza, tj. zamiast update:

Kopiuj
new.days=new.end_date::date - start_date::date;

Czyli zamiast:

Kopiuj
UPDATE test SET days=end_date::date - new.start_date::date;
UPDATE test SET days=new.end_date::date - start_date::date;

Powinno być:

Kopiuj
new.days=end_date::date - new.start_date::date;
new.days=new.end_date::date - start_date::date;

Zgadza się?

Marcin.Miga
  • Rejestracja:prawie 17 lat
  • Ostatnio:4 dni
  • Postów:2792
0

Tylko jęsli modyfikujesz NEW, to musisz mieć triggera BEFORE, w AFTER, to już "after the birds" :)

L8
  • Rejestracja:około 8 lat
  • Ostatnio:prawie 6 lat
  • Postów:99
0
Marcin.Miga napisał(a):

Tylko jęsli modyfikujesz NEW, to musisz mieć triggera BEFORE, w AFTER, to już "after the birds" :)

Zmodyfikowałem całość i w efekcie dostałem error:

ERROR: column "end_date" does not exist
LINE 1: SELECT end_date::date - NEW.start_date::date

QUERY: SELECT end_date::date - NEW.start_date::date
CONTEXT: PL/pgSQL function update_days() line 4 at assignment
********** Błąd **********

ERROR: column "end_date" does not exist
Stan SQL: 42703
Kontekst: PL/pgSQL function update_days() line 4 at assignment

Marcin.Miga
Daj całość funkcji.
L8
CREATE OR REPLACE FUNCTION update_days() RETURNS trigger AS $BODY$ BEGIN IF NEW.start_date <> OLD.start_date THEN NEW.days=end_date::date - NEW.start_date::date; ELSEIF NEW.end_date <> OLD.end_date THEN NEW.days=NEW.end_date::date - start_date::date; END IF; RETURN NEW; END $BODY$ LANGUAGE plpgsql
L8
No nie mogę sobie z tym poradzić...nie chce mi to zadziałać...to powinno działać zamiennie, czyli jeśli robię update kolumny start_date, to nowa wartość w kolumnie days powinna być różnicą między istniejącym end_date a nowym start_date i na odwrót: jeśli robię update end_date, to wartość days powinna być różnicą między istniejącym start_date a nowym end_date.
PA
  • Rejestracja:ponad 22 lata
  • Ostatnio:około 9 godzin
  • Postów:3866
0

Taki off-top pierwszy raz dowiedziałem się, że postgres czegoś nie ma, względem mssql, mam na myśli Computed Columns, co by tu idealnie pasowało. Ma być w wersji 12, chociaż raz nie mam powodów do zazdrości ;)

Marcin.Miga
  • Rejestracja:prawie 17 lat
  • Ostatnio:4 dni
  • Postów:2792
0

@Panczo: ale można to zrobić bez widoków....
Ech, wprowadziłem w błąd. CREATE RULE niejawnie tworzy widok...

edytowany 1x, ostatnio: Marcin.Miga
PA
  • Rejestracja:ponad 22 lata
  • Ostatnio:około 9 godzin
  • Postów:3866
0

Nie wiem o jakich widokach mówisz, nie miałem tez na myśli CREATE RULE, chodzi mi o kolumnę wyliczeniową, czyli bez triggera, rule itd., zakładamy tabele:

Kopiuj
create table dbo.tabela (
 ID int IDENTITY (1,1) NOT NULL  
  , start_date datetime
  , end_date datetime
  , days AS datediff(d,start_date,end_date) PERSISTED,
 
    CONSTRAINT PK_tabela_ID 
        PRIMARY KEY CLUSTERED (ID)
)

wkładamy dane:

Kopiuj
insert into tabela (start_date,end_date) values ('2018-02-02','2018-06-20'),('2018-02-02',null)

i w rezultacie mamy:

Kopiuj
ID,start_date,end_date,days
1,2018-02-02 00:00:00.000,2018-06-20 00:00:00.000,138
2,2018-02-02 00:00:00.000,NULL,NULL
edytowany 1x, ostatnio: Panczo
L8
  • Rejestracja:około 8 lat
  • Ostatnio:prawie 6 lat
  • Postów:99
0

@Panczo: faktycznie, coś takiego idealnie pasowałoby do tego, co chcę osiągnąć. Aż dziwne, że w innych silnikach coś takiego jest, a tutaj nie...Niemniej jednak, to nadal nie działa u mnie, więc szukam dalej pomysłów...

Marcin.Miga
  • Rejestracja:prawie 17 lat
  • Ostatnio:4 dni
  • Postów:2792
0

Bez żadnych IFow.

Kopiuj
New.days = new.end_date-new.start_date;
L8
  • Rejestracja:około 8 lat
  • Ostatnio:prawie 6 lat
  • Postów:99
0
Marcin.Miga napisał(a):

Bez żadnych IFow.

Kopiuj
New.days = new.end_date-new.start_date;

Pięknie dziękuję! Chwilę wcześniej znalazłem dokładnie takie samo rozwiązanie...działa elegancko, zgodnie z założeniami! Zastanawiam się tylko, dlaczego IFy nie chciały tego ogarnąć, zrobiłem jakiś błąd w logice?

hauleth
Moderator
  • Rejestracja:ponad 17 lat
  • Ostatnio:18 dni
0

@Lucas83: zamiast modyfikować wiersz, który wstawiałeś ty robiłeś update:

Kopiuj
UPDATE test SET days=end_date::date - new.start_date::date;

Który jako, że jest unbounded zmieniał wartość we wszystkich wierszach w tabeli.


L8
No tak, jeden update uruchamiający triggera, a potem drugi w funkcji, co było bezsensem z mojej strony :)
Marcin.Miga
  • Rejestracja:prawie 17 lat
  • Ostatnio:4 dni
  • Postów:2792
0
Lucas83 napisał(a):
Marcin.Miga napisał(a):

Bez żadnych IFow.

Kopiuj
New.days = new.end_date-new.start_date;

Pięknie dziękuję! Chwilę wcześniej znalazłem dokładnie takie samo rozwiązanie...działa elegancko, zgodnie z założeniami! Zastanawiam się tylko, dlaczego IFy nie chciały tego ogarnąć, zrobiłem jakiś błąd w logice?

To nie IF były przyczyną błędów, a brak NEW lub OLD. Samo days jest nieznane w triggerze (bo nie pokazujesz z której tabeli/obiektu - nie masz tam np. SELECT)

Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)