Jak załadować TStringList do bazy PostgreSQL?

0

Witam Wszystkich.

Mam pytanie? Czy ktoś może podpowiedzieć jak dane ze TStringList załadować do przykładowej tabeli w postgresql. Dla przykładu podam:

                                                                                                  nr kol   1234  
   sl := TStringList.Create; // w tej liście znajdują się np dwie linijki liczb linia nr 1 2564
                                                                                                 linia nr 2 7198

Chcę, aby każda kolumna mogła być przypisania konkretnej do konkretnego polu w tabeli. Dla przykładu podam:

Niech tabela nazywa się Dane a pola w niej to D_1; D_W1; D_2; D_W2; D_3; D_W3; D_4; D_W4
Chciałby, aby do pól:

 D_W1; D_W2; D_W3; D_W4
  2         5         6         4
  7         1         9         8

Jak widać chcę mieć możliwość sterowania wpisaniem w pętli do pól tabeli konkretnej kolumny z TStringListy. Oczywiście podałem dla przykładu dwa wiersze, domyślacie się że tych wierszy może być 100 000 lub 50 000. Ilość wierszy nie jest istotne. Istotne jest ilość kolumn w TStringList i możliwość przypisania konkretnej kolumny np nr 1 do pola DW_1.
Oczywiście może być tak:

kolumna nr 1 do pola D_W3 itd jeśli się da.

Jeśli nie to po kolei:

kol nr 1 do D_W1;
kol nr 2 do D_W2 ;
kol nr 3 do D_W3 
kol nr 4 do D_W4;

Mam nadzieję że dobrze wytłumaczyłem o co mi chodzi. Z góry dziękuję za pomoc w tej sprawie. Znaki w TSTRINGLIST nie są odzielone niczym tj. spacją czy średnikiem lub innym znakiem. Lista jest zapisana tak : 0256 tak wygląda 1 linia. pod nią kolejna linia 5698 itd.

Dłuższy

0

Procedura dodające dane, za pomoca FireDAC:

procedure TFoo.AppendData(const AST: TStringList; const AFields: string);

  function ParseFields(const AFields: string; const APrefix : string = '') : string;
  var
    lStrArray : TArray<string>;
    I         : Integer;
  begin
    lStrArray := AFields.Split([',', ';'], ExcludeEmpty);

    if not APrefix.IsEmpty then
      for I := Low(lStrArray) to High(lStrArray) do
        lStrArray[i] := APrefix + lStrArray[i];

    Result := Result.Join(', ', lStrArray);
  end;

var
  i       : Integer;
  lCommand: IFDPhysCommand;
  lToken  : string;
  lFields : TArray<string>;
  J       : Integer;
begin
  if Assigned(AST) and (AST.Count > 0) then
  begin
    // conMain, to jest FireDAC Connection
    conMain.ConnectionIntf.CreateCommand(lCommand);
    lCommand.Options.FormatOptions.DefaultParamDataType := ftInteger;
    lCommand.CommandText := Format('insert into Dane(%s) values(%s)', [ParseFields(AFields), ParseFields(AFields, ':')]);
    // Użyj Array DML, będzie bardzo szybko
    lCommand.Params.ArraySize := AST.Count;

    lFields := AFields.Split([',', ';'], ExcludeEmpty);

    i := 0;
    for lToken in AST do
    begin
      for J := Low(lFields) to High(lFields) do
        lCommand.Params[J].Values[i] := lToken.Chars[j];
      Inc(i);
    end;

    lCommand.Execute(lCommand.Params.ArraySize);
  end;
end;

Użycie:

procedure TFooo.Test;
var
  lST: TStringList;
begin
  lST := TStringList.Create;
  try
    lST.Add('1234');
    lST.Add('4562');
    lST.Add('7895');

    AppendData(lST, 'D_W1;D_W2;D_W3;D_W4');
  finally
    lST.Free;
  end;
end;
0

Dzięki za tak szybką reakcję. Przystosowałem kod do moje bazy danych trochę wywala w tym miejscu

  i := 0;
    for lToken in AST do
    begin
      for J := Low(lFields) to High(lFields) do
        lCommand.Params[J].Values[i] := lToken.Chars[j];
      Inc(i);
    end;

Pierwsze przejście pętli jest Ok. zakres Pól liczy od O to jest ok. Przy drugim przejściu gdy J=1 też jest ok, ale przy ostatnim przejściu gdy J=2 wywala błąd:

"Argument out of range" - sygnalizuje przekroczenie tablicy. Na moje potrzeby skróciłem TstringList do dwóch kolumn.

    lST.Add('12');
    lST.Add('45');
    lST.Add('78');

tak więc powinien do tabeli D_W1 przypisać wiersze 1,4,7 , a do tabeli D_W2 przypisać wiersze 2,5,8 oczywiście licząc po kolumnach.

Jeszcze jedno moja lista jest wygenerowana i znajdują się w niej 100000 wierszy w dwóch trzech kolumnach. Mam taki kod do wstawiania listy do Stringgrida a chciałby aby wstawiać do tabeli oczywiście twój patent

AppendData(lST, 'D_W1;D_W2;D_W3;D_W4');

jest Ok po wstawiam kolumny z TStringListy do kolumn które chce i o to chodzi. Ale jakbyś mógł ten kod zamienić na tablę a nie Stringgrida to byłoby ok. Po prostu nie ważne jaka jest TStringLista to zawsze po kolumnach można wstawić do Tabeli.

  // Zliczenie maksymalnelnej liczby kolumn
  iCols := 0;
   for i := 0 to sl.Count-1 do begin
     if Length(sl[i])+1>iCols then
       iCols := Length(sl[i])+1;
  end;

    // numeracja nagłówków kolumn
    for j := 1 to iCols-1 do
     begin
      AdvStringGrid1.Cells[j,0] := IntToStr(j);
     end;

    // Wypełnienie siatki
      AdvStringGrid1.RowCount := sl.Count+1;
      AdvStringGrid1.ColCount := iCols;
      AdvStringGrid1.DefaultColWidth := 18;
      AdvStringGrid1.ColWidths[0] := 64;

 // wstawianeie danych ze zmiennej Sl do Stringgrida
    for i := 0 to sl.Count-1 do
     begin
      ARow := i+1;
      ss := sl[i];
       for j := 1 to Length(ss) do
        begin
        ACol := j;
         AdvStringGrid1.Cells[ACol,ARow] := ss[j];
          AdvStringGrid1.Cells[0,ARow] := Format('%d',[i+1]);
        end;
     end;
   end;

// ten kod chodzi. Twoja propozycja jest lepsza z uwagi na to, że wpisuję pola do których mam być kierowana konkretna kolumna ze zmiennej sl. 

W związku z błędem jaki mi wywala. Może coś robię nie tak, a więc proszę o pomoc. Dla twojej uwagi też korzystam z komponentów FireDac.

Wcześniej nie pokazywałem tego kodu bo chciałem zobaczyć czy ktoś ma inny pomysł na rozwiązanie tego problemu. Uważam że Twoja metoda jest zdecydowanie lepsza niż moja. Poza tym w mojej nie mogę kierować zapisem do konkretnej kolumny i ponadto wpisuje do Stringgrida, a nie do Bazy danych.

Tak więc czekam na podpowiedź no i usunięcie błędu lub wskazanie mojego błędu. Dla jasności procedurę wywołująca przypisałem do Buttona.

procedure TForm1.Button215Click(Sender: TObject);
var
  lST: TStringList;
begin
  lST := TStringList.Create;
  try
    lST.Add('12');
    lST.Add('45');
    lST.Add('78');

    AppendDatabase(lST, 'inwestycje_srednia; eksploatacje_srednia');
  finally
    lST.Free;
  end;
end;

Podziękowania dla user2324 jeśli by Ci nie przeszkadzało prowadzenie korespondencji e-mail to proszę napisz
[email protected]

pozdrawiam
Dluższy

dodanie znaczników <code class="delphi"> i `` - furious programming

0

A ja poproszę, bo przeszkadza tutaj brak tagowania. Abyś powstawiał fragmenty kodu w odpowiednie znaczniki delphi.

0

@dluzszy hmm...
Po pierwsze - niestety nie masz pojęcia jak ten kod działa. Gdybyś miał, to ten błąd wyłapał byś od razu. Wiesz jak się używa debuggera? To go użyj.
Po drugie - to był przykład, a nie gotowe rozwiązanie. Chcesz gotowca? Ok - ile płacisz?
Po trzecie - no ja Cię przerpaszam, ale wyjątki i sprawdzenia możesz chyba zrobic sobie sam, prawda? Specjalnie ich nie robiłem, bo nie znam wymagań. A Twój opis problemu... szkoda komentować.
I po czwarte - w innym poście nie odpowiedziałeś na cholerę chcesz ładować dane do StringGrida, zamiast do DBGrida. Nie tylko nie odpowiedziałeś, ale też pyskowałeś. Nieładnie.

Ale niech będzie;

//MMWIN:CLASSCOPY
unit _MM_Copy_Buffer_;

interface

type
  TFoo = class
  strict private
    type
      EFooException = class(Exception);
    const
      cErr_ParamsCount = 'Niezgodna liczba parametrów dla tokenu [%s].' + sLineBreak +
                         'Ilość wartości w tokenie [%d].' + sLineBreak +
                         'Oczekiwana ilość parametrów w bazie danych [%d].';
      cErr_EmptyFields = 'Nie zdefinowano pól do których mają zostać przypisane dane.';
  strict private
    FConnection: TFDConnection;
  strict protected
    function ParseFields(const AFields: string; const APrefix : string = '') : string;
  public
    constructor Create(AConnection : TFDConnection);
    procedure AppendData(const AST: TStringList; const AFields: string);
  end;

implementation

procedure TFoo.AppendData(const AST: TStringList; const AFields: string);
var
  i       : Integer;
  lCommand: IFDPhysCommand;
  lToken  : string;
  J       : Integer;
begin
  if Assigned(AST) and (AST.Count > 0) then
  begin
    // conMain, to jest FireDAC Connection
    FConnection.ConnectionIntf.CreateCommand(lCommand);
    lCommand.Options.FormatOptions.DefaultParamDataType := ftInteger;
    lCommand.CommandText := Format('insert into Dane(%s) values(%s)', [ParseFields(AFields), ParseFields(AFields, ':')]);
    // Użyj Array DML, będzie bardzo szybko
    lCommand.Params.ArraySize := AST.Count;

    i := 0;
    for lToken in AST do
    begin
      if lToken.Length <> lCommand.Params.Count then
        raise EFooException.CreateFmt(cErr_ParamsCount, [lToken, lToken.Length, lCommand.Params.Count]);

      for J := 0 to lCommand.Params.Count - 1 do
        lCommand.Params[J].Values[i] := lToken.Chars[j];
      Inc(i);
    end;

    lCommand.Execute(lCommand.Params.ArraySize);
  end;
end;

constructor TFoo.Create(AConnection: TFDConnection);
begin
  inherited Create;
  FConnection := AConnection;
end;

function TFoo.ParseFields(const AFields, APrefix: string): string;
var
  lStrArray : TArray<string>;
begin
  if AFields.IsEmpty then
    raise EFooException.Create(cErr_EmptyFields);

  lStrArray    := AFields.Split([',', ';'], ExcludeEmpty);
  lStrArray[0] := APrefix + lStrArray[0];

  Result := Result.Join(', ' + APrefix, lStrArray)
end;

end.

Używasz analogicznie jak poprzednio, z tym że musisz powołać do życia obiekt klasy TFoo - ale to oczywista oczywistość...
Co do ładowania takiej ilośc danych do StringGrida (100K wierszy?); to nie jest dobry pomysł, a jeżeli est tego więcej to powinieneś użyć czegoś co wspiera tryb wirtualny.
A więc będzie to TDrawGrid, TListView lub VirtualTreeView. Z kodu widzę, że używasz StringGrida do TMSa - nie wiem czy on wspiera tryb wirutalny. Jeżeli tak, powinieneś go użyć.

0

Witaj user2324

Na początek wielkie dzięki. Teraz może nie powinienem, ale skoro zaczepiłeś mnie o innego posta. Jak widzisz wszystkie moje posty mają charakter zapytań. Nikogo nie obrażam i nie robię wycieczek personalnych do nikogo, chyba że mnie ktoś zaczepi to też staram się grzecznie odpowiadać. Skoro uważasz że cytat:

" Próbujesz być w [CIACH!] grzeczny aby inni zobaczyli jaki to z ciebie "kurturarny (pisownia zamierzona) dżentelmen" a zamiast tego wychodzi słoma z butów. Takich jak ty, którzy wszystko wiedzą najlepiej a trzech linijek kodu do kupy nie potrafią skleić było tutaj już od groma." Koniec cytatu.
Nie mam zamiaru odpowiadać na zaczepki. Jeżeli ktoś prosi o pomoc bo nie jest tak dobry jak niektóre osoby w sieci. To chyba o to chodzi. Nikt nie prosi o napisanie całego programu tylko o rozwiązanie jakiegoś problemu. Między innymi po to powstał internet.

Teraz odnośnie debuggera oczywiście, że to robiłem ponieważ, skąd bym widział w którym miejscu wywala się kod i przecież wstawiłem linijkę. I na koniec. Myślę że skromność jest największą cechą człowiek. Pomoc drugiem jest czymś co budzi wielki szacunek. Tobie i wszystkim, którzy pomagają innym wielkie dzięki. Do pozostałych spraw nie chcę się odnosić.

pozdrawiam

Dluższy

0
dluzszy napisał(a):

Witaj user2324
Na początek wielkie dzięki. Teraz może nie powinienem, ale skoro zaczepiłeś mnie o innego posta. Jak widzisz wszystkie moje posty mają charakter zapytań. Nikogo nie obrażam i nie robię wycieczek personalnych do nikogo, chyba że mnie ktoś zaczepi to też staram się grzecznie odpowiadać.

To Twoja opinia - inni mieli inną na ten sam temat.

Skoro uważasz że cytat:
" Próbujesz być w [CIACH!] grzeczny aby inni zobaczyli jaki to z ciebie "kurturarny (pisownia zamierzona) dżentelmen" a zamiast tego wychodzi słoma z butów. Takich jak ty, którzy wszystko wiedzą najlepiej a trzech linijek kodu do kupy nie potrafią skleić było tutaj już od groma." Koniec cytatu.

Oczywiście, tak było. Tylko, jakim cudem zapomniałeś wcześniejszych wpisów swoich i innych, które są istotne i doprowadziły do takiego wpisu?
Szczerze - zasłużyłeś sobie na takie traktowanie i nie jesteś bez winy.
Zresztą, co mnie to....

Nie mam zamiaru odpowiadać na zaczepki. Jeżeli ktoś prosi o pomoc bo nie jest tak dobry jak niektóre osoby w sieci. To chyba o to chodzi. Nikt nie prosi o napisanie całego programu tylko o rozwiązanie jakiegoś problemu. Między innymi po to powstał internet.

Wiesz co, odrobinę pokory by Ci się przydało bo masz strasznie irytujące bicia.
Skoro wiesz, że nie wiesz i prosisz o pomoc, to dostosuj się do tych, którzy chcą i wiedza jak Ci pomóc. Nawet, jeśli Ci się to nie podoba.
A jak Ci się nie podoba, to nie zawracaj nikomu doopy i też będzie dobrze.

Teraz odnośnie debuggera oczywiście, że to robiłem ponieważ, skąd bym widział w którym miejscu wywala się kod i przecież wstawiłem linijkę.

I nie poprawiłeś "błędu", który błędem nie był.
Nie odpowiedziałeś na pytanie - wiesz dokładnie jak ten kod działa?

I na koniec. Myślę że skromność jest największą cechą człowiek. Pomoc drugiem jest czymś co budzi wielki szacunek. Tobie i wszystkim, którzy pomagają innym wielkie dzięki. Do pozostałych spraw nie chcę się odnosić.

Skoro wyznajesz taką szczytną zasadę to, dlaczego jej nie hołdujesz? Wybacz, ale skromny to Ty na pewno nie jesteś - sądząc po tym co i w jaki sposób piszesz. Ale to moja opinia ;-)

I na koniec - zaspokoisz moją ciekawość i powiesz mi dlaczego uparłeś sią na ładowanie danych do StringGrida?
Jeżeli opiszesz wszystko ślicznie, czyli bez skrótów myślowych, od których roi się w Twoich opisach! Zauważ, że my nie wiemy, co dokładnie masz zrobić, a najgorsze co możesz powiedzieć - to "nie chcę o tym mówić, bo to nieistotne dla istoty problemu".
Tak więc opisz dokładnie co robisz i dlaczego tak jak sześciolatkowi, a ja Ci pokażę jak ładować te dane do StingGrida tak jak chcesz. Pod warunkiem, że dalej będziesz chciał i opiszesz to w sposób zrozumiały.

0

@user2324</span></b> - przypominam o zachowaniu kultury i pozostaniu przy rozwiązywaniu problemu, a nie dyskusji na tematy niezwiązane z poruszanym problemem; Jeżeli nie podoba Ci się cokolwiek w wypowiedziach pytacza czy kogokolwiek innego, to albo zgłoś to moderacji, albo po prostu skończ się udzielać w tym wątku; Twoja kultura też pozostawia wiele do życzenia, więc dopóki sam nie będziesz umieszczać kulturalnych wypowiedzi, to zakończ upominanie innych;

Po drugie nie omijaj cenzury - po to ona jest, aby zwroty takie jak d*** były maskowane; Jeżeli nie potrafisz zachować choćby pozorów bycia kulturalnym i inteligentnym - skończ się wypowiadać; Odciągasz uwagę od poruszanego problemu i prowokujesz do offtopu, więc następne tego typu posty będą kasowane;

Próbujesz być w [CIACH!] grzeczny aby inni zobaczyli jaki to z ciebie "kurturarny (pisownia zamierzona) dżentelmen" a zamiast tego wychodzi słoma z butów. Takich jak ty, którzy wszystko wiedzą najlepiej a trzech linijek kodu do kupy nie potrafią skleić było tutaj już od groma.

Nie wiem czyj to cytat, ale łby polecą, jeśli ktokolwiek będzie się w ten sposób wypowiadał; Jeśli komuś coś u kogoś nie pasuje, to proszę się upominać w PM'kach, a nie w publicznej części serwisu; Forum jest po to, aby rozwiązywać problemy dotyczące programowania;

Poza tym w wypowiedziach @dluzszy'ego nie widzę wypowiedzi niekulturalnych, wręcz przeciwnie;

Podsumowując - koniec offtopu; Albo dyskusja będzie dotyczyć pierwotnego problemu, albo wątek zostanie zamknięty i nic nie wnoszące do tematu posty zostaną skasowane.

0

Chyba nastąpiła blokada tego wątku. Nie mogę udzielić odpowiedzi.
Dluzszy.

0

User2324. Wielkie dzięki za podpowiedz. Nie chcę odnosić się do uwag. Wcześniej napisałem, ale mój post został przyblokowany. Tak więc kończę wycieczki personalne, których mam nadzieję nie używałem jak to stwierdził "Furious Programming".

Do rzeczy:

  1. Po co mi Stringgrid. Odpowiadając krótko, ponieważ nie tylko mogę edytować dane, ale jeszcze ładnie prezentować. Jak zauważyłeś korzystam z komponentów TMS i dzięki nim mogę szybko i ładnie prezentować dane. Bo nie tylko chodzi o pokazanie danych, tak jak jest to w DBgrid, w każdym razie o to mi też chodzi. Ale mój problem został rozwiązany przez "Johnny_Bit" i tyle w tym temacie. W jednym z postów podał procedurę, jak to zrobić i pięknie chodzi.

  2. Mój problem polega na tym, abym zmienną TStringList w której znajduje się np. 5 kolumn i 10 000 wierszy tj. razem 50 000 znaków mógł wczytać do pola w Tabeli bazy danych, w tym wypadku do PostgresSql za pomocą FireDac. I dzięki Tobie próbuję to zrealizować na tyle ile potrafię. Podałeś parę "patentów", jak się do tego zabrać i dzięki za to. Tak jak powiedziałeś opisałem mój problem.

Linia

 AppendDatabase(lST, 'D_W1;D_W2;D_W3;D_W4'); 

jest jednym z tych patentów. Staram się Twoje drugie rozwiązanie zaimplementować, pewnie mi zejdzie o ile w ogóle to zrobię. Ponieważ tamten kod wbrew temu co pisałeś zrozumiałem - myślę o idei. Pisząc, że coś wywala nie miałem nic złego na myśli, ponieważ byłem przekonany, że pójdzie. Oczywiście, że nie mam takiej wiedzy jak Ty, gdybym ją miał, to nie prosiłbym o podpowiedź, jak do tego problemu się zabrać. Twoja druga wersja jest inna. Próbuję ją zaimplementować i rozgryźć na ile potrafię.

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0