🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Thread View: pl.comp.lang.delphi.bazy-danych
14 messages
14 total messages Started by Tygrys Mon, 21 Jul 2014 19:42
UpdateSQL (FireDac)
#82199
Author: Tygrys
Date: Mon, 21 Jul 2014 19:42
20 lines
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)
#82200
Author: wloochacz
Date: Mon, 21 Jul 2014 20:07
24 lines
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)
#82201
Author: Tygrys
Date: Mon, 21 Jul 2014 20:51
13 lines
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)
#82202
Author: wloochacz
Date: Mon, 21 Jul 2014 21:05
31 lines
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)
#82203
Author: Tygrys
Date: Tue, 22 Jul 2014 11:00
49 lines
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)
#82204
Author: Arivald
Date: Tue, 22 Jul 2014 11:26
58 lines
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)
#82208
Author: miab
Date: Tue, 22 Jul 2014 11:58
29 lines
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)
#82205
Author: wloochacz
Date: Tue, 22 Jul 2014 12:27
19 lines
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)
#82206
Author: Tygrys
Date: Tue, 22 Jul 2014 14:58
19 lines
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)
#82207
Author: Arivald
Date: Tue, 22 Jul 2014 15:31
17 lines
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)
#82209
Author: Tygrys
Date: Tue, 22 Jul 2014 20:45
42 lines
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)
#82210
Author: miab
Date: Tue, 22 Jul 2014 22:54
55 lines
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)
#82211
Author: Tygrys
Date: Wed, 23 Jul 2014 10:29
23 lines
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)
#82212
Author: miab
Date: Wed, 23 Jul 2014 12:18
31 lines
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