Thread View: pl.comp.lang.delphi.bazy-danych
14 messages
14 total messages
Started by Tygrys
Mon, 21 Jul 2014 19:42
UpdateSQL (FireDac)
Author: Tygrys
Date: Mon, 21 Jul 2014 19:42
Date: Mon, 21 Jul 2014 19:42
20 lines
1818 bytes
1818 bytes
Mam niemodyfikowalną tabelę t1 o strukturze typu Id, Nazwa. Mam drugą tabelę t2 o strukturze Id, Komentarz - na początku ta tabela jest pusta - albo mało zapełniona w porównaniu do tej pierwszej. Baza SQLite. Wyświetlam w gridzie (cxDBTableView) takie zapytanie: Select t1.nazwa, t2.komentarz from t1 left join t2 on t1.id=t2.id Jeżeli teraz dopiszę do jakiejś nazwy komentarz w tej tabelce to chciałbym, żeby dopisał się pod odpowiednim id w tabeli t2. Jak skonstruować do tego UpdateSQL ? Problem na jaki się natknąłem to to, że w momencie dopisywania komentarza automatycznie generowane jest update tabeli t2, a potrzebny często jest insert. Na razie robię to przez OnUpdateRecord - ale może jest jakaś "lepsza" implementacja?
Re: UpdateSQL (FireDac)
Author: wloochacz
Date: Mon, 21 Jul 2014 20:07
Date: Mon, 21 Jul 2014 20:07
24 lines
2094 bytes
2094 bytes
W dniu 2014-07-21 21:42, Tygrys pisze: > Problem na jaki się natknąłem to to, że w momencie dopisywania > komentarza automatycznie generowane jest update tabeli t2, a potrzebny > często jest insert. > > Na razie robię to przez OnUpdateRecord - ale może jest jakaś "lepsza" > implementacja? W UpdateSQL możesz wpisać jakikolwiek poprawny SQL (oczywiście z rodziny DML), może to być batch, blok czy procedura składowana. Możesz wpisać kawał skryptu z deklaracją zmiennych i czym tam jeszcze baza dysponuje (returning też działa). Coś takiego też powinno iść: if exists (select * from t2.* where id = :NEW_ID) update t2 set komentarz = :NEW_KOMENTARZ else insert into t2(id, komentarz) values(:NEW_ID, :NEW_KOMENTARZ) Nie wiem czy SQLite posiada odpowiednik MERGE, ale zawsze możesz po prostu wywołać procedurę... -- wloochacz
Re: UpdateSQL (FireDac)
Author: Tygrys
Date: Mon, 21 Jul 2014 20:51
Date: Mon, 21 Jul 2014 20:51
13 lines
1779 bytes
1779 bytes
W dniu 2014-07-21 22:07, wloochacz pisze: > > Coś takiego też powinno iść: > if exists (select * from t2.* where id = :NEW_ID) > update t2 set komentarz = :NEW_KOMENTARZ > else > insert into t2(id, komentarz) values(:NEW_ID, :NEW_KOMENTARZ) > Prawie... też tak kombinowałem. Problemem w tej składni jest to, że de facto nie mamy tego :New_ID. Dysponujemy tylko t1.id - który by należało jakoś do t2.id przepisać. No i czy jakoś nie musi to id wtedy wystąpić w selekcie?
Re: UpdateSQL (FireDac)
Author: wloochacz
Date: Mon, 21 Jul 2014 21:05
Date: Mon, 21 Jul 2014 21:05
31 lines
2556 bytes
2556 bytes
W dniu 2014-07-21 22:51, Tygrys pisze: > W dniu 2014-07-21 22:07, wloochacz pisze: >> >> Coś takiego też powinno iść: >> if exists (select * from t2.* where id = :NEW_ID) >> update t2 set komentarz = :NEW_KOMENTARZ >> else >> insert into t2(id, komentarz) values(:NEW_ID, :NEW_KOMENTARZ) >> > Prawie... też tak kombinowałem. > Problemem w tej składni jest to, że de facto nie mamy tego :New_ID. Jak nie masz, jak masz? Przecież jakoś go dostajesz, prawda? Jeżeli id nadaje baza, to musisz go pobrać w tym SQLUpdate - pisałem o returning, zauważyłeś? Ale w tym przypadku chyba coś takiego nie będzie potrzebne... > Dysponujemy tylko t1.id - który by należało jakoś do t2.id przepisać. To jest to samo ID, a przynajmniej ja to tak rozumiem. Skoro jest to to samo, to parametr nawiązuje do pola z SELECT - i może to być ID z T1. > No i czy jakoś nie musi to id wtedy wystąpić w selekcie? Musi być w DataSet - czyli najprościej tak, musi być w select. PS. Zawsze możesz wrzucić gdzieś kompletny testowy projekt, a wtedy będzie łatwiej. -- wloochacz
Re: UpdateSQL (FireDac)
Author: Tygrys
Date: Tue, 22 Jul 2014 11:00
Date: Tue, 22 Jul 2014 11:00
49 lines
3090 bytes
3090 bytes
W dniu 2014-07-21 23:05, wloochacz pisze:
> W dniu 2014-07-21 22:51, Tygrys pisze:
>> W dniu 2014-07-21 22:07, wloochacz pisze:
>>>
>>> Coś takiego też powinno iść:
>>> if exists (select * from t2.* where id = :NEW_ID)
>>> update t2 set komentarz = :NEW_KOMENTARZ
>>> else
>>> insert into t2(id, komentarz) values(:NEW_ID, :NEW_KOMENTARZ)
>>>
>> Prawie... też tak kombinowałem.
>> Problemem w tej składni jest to, że de facto nie mamy tego :New_ID.
> Jak nie masz, jak masz?
> Przecież jakoś go dostajesz, prawda?
> Jeżeli id nadaje baza, to musisz go pobrać w tym SQLUpdate - pisałem o
> returning, zauważyłeś?
> Ale w tym przypadku chyba coś takiego nie będzie potrzebne...
Słusznie.
>
>> Dysponujemy tylko t1.id - który by należało jakoś do t2.id przepisać.
> To jest to samo ID, a przynajmniej ja to tak rozumiem.
> Skoro jest to to samo, to parametr nawiązuje do pola z SELECT - i może
> to być ID z T1.
>
>> No i czy jakoś nie musi to id wtedy wystąpić w selekcie?
> Musi być w DataSet - czyli najprościej tak, musi być w select.
No to jest pierwszy istotny punkt tej łamigłówki. :-)
SELECT t1.id, t1.nazwa, t2.komentarz
FROM t1 LEFT JOIN t2 on t1.id = t2.id
>
> PS.
> Zawsze możesz wrzucić gdzieś kompletny testowy projekt, a wtedy będzie
> łatwiej.
No jest łatwiej, bo jak już zrobiłem ten testowy projekt to się udało
dojść do sedna.
Rozwiązaniem - dla SQLite jest ModifySQL o wartości
insert or replace into t2(id, komentarz) values(:NEW_ID, :NEW_KOMENTARZ)
składnia zaproponowana przez wloochacza akurat dla sqlite nie działa.
Żeby jednak taka konstrukcja działała poprawnie to pole id w t2 musi być
zadeklarowane jako klucz - inaczej każda modyfikacja jest traktowana jak
insert.
Dzięki wloochacz za inspiracje i wyjaśnienie. :-)
Re: UpdateSQL (FireDac)
Author: Arivald
Date: Tue, 22 Jul 2014 11:26
Date: Tue, 22 Jul 2014 11:26
58 lines
3351 bytes
3351 bytes
On 2014-07-22 13:00, Tygrys wrote: > W dniu 2014-07-21 23:05, wloochacz pisze: >> W dniu 2014-07-21 22:51, Tygrys pisze: >>> W dniu 2014-07-21 22:07, wloochacz pisze: >>>> >>>> Coś takiego też powinno iść: >>>> if exists (select * from t2.* where id = :NEW_ID) >>>> update t2 set komentarz = :NEW_KOMENTARZ >>>> else >>>> insert into t2(id, komentarz) values(:NEW_ID, :NEW_KOMENTARZ) >>>> >>> Prawie... też tak kombinowałem. >>> Problemem w tej składni jest to, że de facto nie mamy tego :New_ID. >> Jak nie masz, jak masz? >> Przecież jakoś go dostajesz, prawda? >> Jeżeli id nadaje baza, to musisz go pobrać w tym SQLUpdate - pisałem o >> returning, zauważyłeś? >> Ale w tym przypadku chyba coś takiego nie będzie potrzebne... > Słusznie. >> >>> Dysponujemy tylko t1.id - który by należało jakoś do t2.id przepisać. >> To jest to samo ID, a przynajmniej ja to tak rozumiem. >> Skoro jest to to samo, to parametr nawiązuje do pola z SELECT - i może >> to być ID z T1. > >> >>> No i czy jakoś nie musi to id wtedy wystąpić w selekcie? >> Musi być w DataSet - czyli najprościej tak, musi być w select. > > No to jest pierwszy istotny punkt tej łamigłówki. :-) > SELECT t1.id, t1.nazwa, t2.komentarz > FROM t1 LEFT JOIN t2 on t1.id = t2.id >> >> PS. >> Zawsze możesz wrzucić gdzieś kompletny testowy projekt, a wtedy będzie >> łatwiej. > No jest łatwiej, bo jak już zrobiłem ten testowy projekt to się udało > dojść do sedna. > > Rozwiązaniem - dla SQLite jest ModifySQL o wartości > > insert or replace into t2(id, komentarz) values(:NEW_ID, :NEW_KOMENTARZ) > > składnia zaproponowana przez wloochacza akurat dla sqlite nie działa. > > Żeby jednak taka konstrukcja działała poprawnie to pole id w t2 musi być > zadeklarowane jako klucz - inaczej każda modyfikacja jest traktowana jak > insert. Czyli to jest 1:1 ? to po co dwie tabele? Sensowniej jest albo jedna tabela, albo 1:many, wtedy żeby "insert or replace" działało to trzeba dodać pkey do tabeli komentarzy, a istniejące id zmienić na id_nazwy, foreign key. Oczywiście join w select też trzeba będzie zmienić. -- Arivald
Re: UpdateSQL (FireDac)
Author: miab
Date: Tue, 22 Jul 2014 11:58
Date: Tue, 22 Jul 2014 11:58
29 lines
2357 bytes
2357 bytes
W dniu 2014-07-21 21:42, Tygrys pisze: > Mam niemodyfikowalną tabelę t1 o strukturze typu Id, Nazwa. > Mam drugą tabelę t2 o strukturze Id, Komentarz - na początku ta tabela > jest pusta - albo mało zapełniona w porównaniu do tej pierwszej. > > Baza SQLite. > Wyświetlam w gridzie (cxDBTableView) takie zapytanie: > > Select t1.nazwa, t2.komentarz from t1 left join t2 on t1.id=t2.id > > Jeżeli teraz dopiszę do jakiejś nazwy komentarz w tej tabelce to > chciałbym, żeby dopisał się pod odpowiednim id w tabeli t2. > > Jak skonstruować do tego UpdateSQL ? > > Problem na jaki się natknąłem to to, że w momencie dopisywania > komentarza automatycznie generowane jest update tabeli t2, a potrzebny > często jest insert. > > Na razie robię to przez OnUpdateRecord - ale może jest jakaś "lepsza" > implementacja? A ja nie wiem dlaczego w t2 masz dziury w numeracji. Specjalnie dużo miejsca na samych identyfikatorach nie oszczędzasz, chyba że rzeczywiście te komentarze są b.rzadko, mało tego nie bardzo rozumiem dlaczego te tabele są rozdzielone. Jaki wogóle jest typ pola Komentarz? miab
Re: UpdateSQL (FireDac)
Author: wloochacz
Date: Tue, 22 Jul 2014 12:27
Date: Tue, 22 Jul 2014 12:27
19 lines
2081 bytes
2081 bytes
W dniu 2014-07-22 13:26, Arivald pisze: > Czyli to jest 1:1 ? to po co dwie tabele? Nie wiem jak u Tygrysa, ale u mnie... Bo tak jest wygodniej ;-) Stosuję takie rozwiązanie jako analogię polimorfizmu; mam np. tabelę tDocHDr w której są podstawowe infomracje (numer, data, typ, status, itd.) dla nagłówków dokumentów wszelkich. Ale np. takie dokumenty handlowe swoje dedykowane wartości trzymają w tabeli tDocHdr i tDocHdrSales - i to jest 1:1. Analogicznie dokumenty produkcyjne są w tDocHdrMrp itd. W ten sposób rdzeń jest ten sam, ale dodatki gdzie indziej. Mógłbym to scalić w jedną tabelę, ale nie chciałem - bo i w programie to de-facto polimorfizmem załatwiam, dzedzicząc funkcjonlaność podstawową. I własnie po to. -- wloochacz
Re: UpdateSQL (FireDac)
Author: Tygrys
Date: Tue, 22 Jul 2014 14:58
Date: Tue, 22 Jul 2014 14:58
19 lines
2139 bytes
2139 bytes
W dniu 2014-07-22 13:26, Arivald pisze: > On 2014-07-22 13:00, Tygrys wrote: > Czyli to jest 1:1 ? to po co dwie tabele? To jest 1:0/1 Czyli masz dużą tabelę z jakiegoś neta czy bazy danych (lokalną kopię) i dołączasz do niektórych rekordów użyteczne dla ciebie dane. Danych z tej pierwszej tabeli nie ma co edytować, bo i tak się "odświeżą" przy kolejnym pobraniu kopii. > > Sensowniej jest albo jedna tabela, albo 1:many, wtedy żeby "insert or > replace" działało to trzeba dodać pkey do tabeli komentarzy, a > istniejące id zmienić na id_nazwy, foreign key. > Oczywiście join w select też trzeba będzie zmienić. > pkey na id dodałem i to oczywiście było potrzebne. 1:n tu nie zachodzi akurat
Re: UpdateSQL (FireDac)
Author: Arivald
Date: Tue, 22 Jul 2014 15:31
Date: Tue, 22 Jul 2014 15:31
17 lines
1735 bytes
1735 bytes
On 2014-07-22 16:58, Tygrys wrote: > W dniu 2014-07-22 13:26, Arivald pisze: >> On 2014-07-22 13:00, Tygrys wrote: > >> Czyli to jest 1:1 ? to po co dwie tabele? > > To jest 1:0/1 > > Czyli masz dużą tabelę z jakiegoś neta czy bazy danych (lokalną kopię) i > dołączasz do niektórych rekordów użyteczne dla ciebie dane. Danych z tej > pierwszej tabeli nie ma co edytować, bo i tak się "odświeżą" przy > kolejnym pobraniu kopii. Ok, rozumiem, w takim kontekście to bardzo sensowne. -- Arivald
Re: UpdateSQL (FireDac)
Author: Tygrys
Date: Tue, 22 Jul 2014 20:45
Date: Tue, 22 Jul 2014 20:45
42 lines
2997 bytes
2997 bytes
W dniu 2014-07-22 13:58, miab pisze: > W dniu 2014-07-21 21:42, Tygrys pisze: >> Mam niemodyfikowalną tabelę t1 o strukturze typu Id, Nazwa. >> Mam drugą tabelę t2 o strukturze Id, Komentarz - na początku ta tabela >> jest pusta - albo mało zapełniona w porównaniu do tej pierwszej. >> >> Baza SQLite. >> Wyświetlam w gridzie (cxDBTableView) takie zapytanie: >> >> Select t1.nazwa, t2.komentarz from t1 left join t2 on t1.id=t2.id >> >> Jeżeli teraz dopiszę do jakiejś nazwy komentarz w tej tabelce to >> chciałbym, żeby dopisał się pod odpowiednim id w tabeli t2. >> >> Jak skonstruować do tego UpdateSQL ? >> >> Problem na jaki się natknąłem to to, że w momencie dopisywania >> komentarza automatycznie generowane jest update tabeli t2, a potrzebny >> często jest insert. >> >> Na razie robię to przez OnUpdateRecord - ale może jest jakaś "lepsza" >> implementacja? > > A ja nie wiem dlaczego w t2 masz dziury w numeracji. > Specjalnie dużo miejsca na samych identyfikatorach nie oszczędzasz, > chyba że rzeczywiście te komentarze są b.rzadko, mało tego nie bardzo > rozumiem dlaczego te tabele są rozdzielone. > Jaki wogóle jest typ pola Komentarz? > > miab Przedstawiona sytuacja jest modelowa, rzeczywista implementacja jest trochę bardziej skomplikowana. Tabele są rozdzielone, bo ta jedna duża jest w postaci zapytania łączącego kilka tabel pobranych z netu które co jakiś (rzadki) czas pobiera się na nowo. Natomiast ta mała to adnotacje do niektórych rekordów dużej. I musi przeżyć aktualizację plików składających się na tą dużą. Pole komentarz to taki przykład, w rzeczywistości tych pól jest więcej. Generalnie jakieś varchary. To ma znaczenie?
Re: UpdateSQL (FireDac)
Author: miab
Date: Tue, 22 Jul 2014 22:54
Date: Tue, 22 Jul 2014 22:54
55 lines
3515 bytes
3515 bytes
W dniu 2014-07-22 22:45, Tygrys pisze:
> W dniu 2014-07-22 13:58, miab pisze:
>> W dniu 2014-07-21 21:42, Tygrys pisze:
>>> Mam niemodyfikowalną tabelę t1 o strukturze typu Id, Nazwa.
>>> Mam drugą tabelę t2 o strukturze Id, Komentarz - na początku ta tabela
>>> jest pusta - albo mało zapełniona w porównaniu do tej pierwszej.
>>>
>>> Baza SQLite.
>>> Wyświetlam w gridzie (cxDBTableView) takie zapytanie:
>>>
>>> Select t1.nazwa, t2.komentarz from t1 left join t2 on t1.id=t2.id
>>>
>>> Jeżeli teraz dopiszę do jakiejś nazwy komentarz w tej tabelce to
>>> chciałbym, żeby dopisał się pod odpowiednim id w tabeli t2.
>>>
>>> Jak skonstruować do tego UpdateSQL ?
>>>
>>> Problem na jaki się natknąłem to to, że w momencie dopisywania
>>> komentarza automatycznie generowane jest update tabeli t2, a potrzebny
>>> często jest insert.
>>>
>>> Na razie robię to przez OnUpdateRecord - ale może jest jakaś "lepsza"
>>> implementacja?
>>
>> A ja nie wiem dlaczego w t2 masz dziury w numeracji.
>> Specjalnie dużo miejsca na samych identyfikatorach nie oszczędzasz,
>> chyba że rzeczywiście te komentarze są b.rzadko, mało tego nie bardzo
>> rozumiem dlaczego te tabele są rozdzielone.
>> Jaki wogóle jest typ pola Komentarz?
>>
>> miab
>
> Przedstawiona sytuacja jest modelowa, rzeczywista implementacja jest
> trochę bardziej skomplikowana.
>
> Tabele są rozdzielone, bo ta jedna duża jest w postaci zapytania
> łączącego kilka tabel pobranych z netu które co jakiś (rzadki) czas
> pobiera się na nowo. Natomiast ta mała to adnotacje do niektórych
> rekordów dużej. I musi przeżyć aktualizację plików składających się na
> tą dużą.
>
> Pole komentarz to taki przykład, w rzeczywistości tych pól jest więcej.
> Generalnie jakieś varchary. To ma znaczenie?
Jeśli tych pól jest więcej to ma kapitalne znaczenie bo wtedy INSERT OR
UPDATE zaczyna się komplikować. Np. dla ID i dwu dodatkowych P1 i P2
żeby utworzyć nowy rekord lub zmodyfikować tylko P1 powinieneś zrobić tak:
INSERT OR REPLACE INTO t2 (ID, P1, P2)
VALUES ( ID_z_t1,
:P1,
(SELECT P2 FROM t2 WHERE ID = ID_z_t1)
);
miab
Re: UpdateSQL (FireDac)
Author: Tygrys
Date: Wed, 23 Jul 2014 10:29
Date: Wed, 23 Jul 2014 10:29
23 lines
2605 bytes
2605 bytes
W dniu 2014-07-23 00:54, miab pisze: > W dniu 2014-07-22 22:45, Tygrys pisze: >> Pole komentarz to taki przykład, w rzeczywistości tych pól jest więcej. >> Generalnie jakieś varchary. To ma znaczenie? > > Jeśli tych pól jest więcej to ma kapitalne znaczenie bo wtedy INSERT OR > UPDATE zaczyna się komplikować. Np. dla ID i dwu dodatkowych P1 i P2 > żeby utworzyć nowy rekord lub zmodyfikować tylko P1 powinieneś zrobić tak: > > INSERT OR REPLACE INTO t2 (ID, P1, P2) > VALUES ( ID_z_t1, > :P1, > (SELECT P2 FROM t2 WHERE ID = ID_z_t1) > ); > Rozumiem tą koncepcję, ale akurat wszystkie te pola są użyte w datasecie - tak że update całości metodą INSERT OR REPLACE niczego nie "zje". SQLite akurat nie ma tych if exists, bo jakby miał to oczywiście rozwiązanie wloochacza jest najbardziej odpowiednie. INSERT OR REPLACE ma tą cechę, że działa jak DETETE-INSERT jak mu sam insert nie wyjdzie.
Re: UpdateSQL (FireDac)
Author: miab
Date: Wed, 23 Jul 2014 12:18
Date: Wed, 23 Jul 2014 12:18
31 lines
2566 bytes
2566 bytes
W dniu 2014-07-23 12:29, Tygrys pisze: > W dniu 2014-07-23 00:54, miab pisze: >> W dniu 2014-07-22 22:45, Tygrys pisze: >>> Pole komentarz to taki przykład, w rzeczywistości tych pól jest więcej. >>> Generalnie jakieś varchary. To ma znaczenie? >> >> Jeśli tych pól jest więcej to ma kapitalne znaczenie bo wtedy INSERT OR >> UPDATE zaczyna się komplikować. Np. dla ID i dwu dodatkowych P1 i P2 >> żeby utworzyć nowy rekord lub zmodyfikować tylko P1 powinieneś zrobić >> tak: >> >> INSERT OR REPLACE INTO t2 (ID, P1, P2) >> VALUES ( ID_z_t1, >> :P1, >> (SELECT P2 FROM t2 WHERE ID = ID_z_t1) >> ); >> > Rozumiem tą koncepcję, ale akurat wszystkie te pola są użyte w datasecie > - tak że update całości metodą INSERT OR REPLACE niczego nie "zje". > > SQLite akurat nie ma tych if exists, bo jakby miał to oczywiście > rozwiązanie wloochacza jest najbardziej odpowiednie. > > INSERT OR REPLACE ma tą cechę, że działa jak DETETE-INSERT jak mu sam > insert nie wyjdzie. Zrozumiałem ze chciałeś updateować/insertować bez czytania. Ale skoro i tak czytasz to zwykły insert lub update wystarcza. miab
Thread Navigation
This is a paginated view of messages in the thread with full content displayed inline.
Messages are displayed in chronological order, with the original post highlighted in green.
Use pagination controls to navigate through all messages in large threads.
Back to All Threads