Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Obliczenia dla wszystkich wierszy
Forum PHP.pl > Forum > Bazy danych
tmk
Witam,
mam w bazie ok 100 000 rekordów, potrzebuję policzyć i wstawić w nowe pole(narazie puste)zmienę procentową. Czy np:
1. wart1, zm_proc=0
2. wart2, zm_proc2=( ((wart2-wart1)/wart1)*100)
...
...
itd.

jak można sprytonie napisać funkcję(może być php), żeby poleciała po wszystkich wierszach i dopisała te zmiany proc.?
ma ktoś pomysł?

z góry dzięki
Method
create procedure
i pare if'ow
dla 100 tys rekordow da rade dla wiekszej liczby trzeba by bylo podzielic zakresami np od id 1 do id = 10000
Jabol
Spróbuj za pomocą kursorów:DECLARE, FETCH. Możesz sobie napisać funckje pgsql i zrobić to w pętli, ale w php też ujdzie, a cursory mają to do siebie, że gdybyś robił to w php to nie będzie zaśmiecać pamięci.
Kod
Deklaracja kursora: cur1 (dla SELECT id, wart FROM tabela);
Zmienna dla bieżącego wiersza: crow;
Zmienna dla poprzedniego wiersza: prow;
#zaczynamy zabawę
prow = FETCH NEXT FROM cur1;
UPDATE tabela SET zm_proc=0 WHERE id=prow.id;
WHILE((crow=FETCH NEXT FROM cur1) IS NOT NULL) DO:
UPDATE table SET zm_proc=(((crow.wart-prow.wart)/prow.wart)*100) WHERE id=crow.id;
prow=crow;
DONE;
CLOSE cur1;
Tak by to mnie więcej wyglądało w pseudokodzie.
SongoQ
Takie cos jeszczcze lepiej jest zrobic zapytaniem.
Jabol
Cytat(SongoQ @ 2005-07-22 12:49:39)
Takie cos jeszczcze lepiej jest zrobic zapytaniem.

jakim?
myślałem o, ale nie wiem czy zadziała.
  1. UPDATE tabela AS cur SET cur.zm_proc=((cur.wart-NULLIF(prev.wart, 0))/NULLIF(prev.wart, 0))*100
  2. FROM tabela AS prev WHERE cur.id=(prev.id+1);
Nigdy nie wykorzystywałem więcej tabel przy UPDATE i nie wiem co będzie z pierwszym rekordem, który swojego poprzednika nie ma.
SongoQ
Cytat
Nigdy nie wykorzystywałem więcej tabel przy UPDATE i nie wiem co będzie z pierwszym rekordem, który swojego poprzednika nie ma.


Zapytanie ok, a z tym pierwszym rekordem to tak ze jesli nie ma dopasowania to zostawi wartosc taka jaka byla wczesniej.

Probem bedzie wtedy jesli beda jakies dziury w id.
Jabol
  1. SELECT DISTINCT ON (test1.f1) *
  2. FROM test AS test1, (SELECT -1 AS f1, NULL AS f2 UNION SELECT f1, f2
  3. FROM test ORDER BY f1) AS test2 WHERE (test1.f1-test2.f1)>0 ORDER BY test1.f1, (test1.f1-test2.f1) ASC;
Po pierwsze wyjaśnienia. kolumne id reprezentuje f1, kolumne wart f2.
No więc tak, oto zapytanie, które pozwala wyciągnąć taki ciąg złożony z rekordu + poprzednika pod pgsql'em, nawet jeżeli są dziury w id. Niestety wyrażenie DISTINCT ON nie jest częścią standartu SQL, a jak na razie nie wymyśliłem jeszcze jakby to DISTINCT ON wyeliminować. Tutaj oczywiście odpada możliwość UPDATE, ale możemy zrobić nową tabelę o innej nazwie z takimi samymi kolumnami + kolumną zm_proc:
  1. SELECT
  2. INTO nowa_tabela tutaj, wyliczamy, wszystkie, pola, wart1 AS wart, (((wart2-wart1)/wart1)*100)::integer AS zm_proc
  3. FROM (SELECT DISTINCT ON (tabela1.f1) tabela1.*, tabela1.f2 AS wart1, tabela2.f2 AS wart2
  4. FROM tabela AS tabela1, (SELECT -1 AS f1, NULL AS f2 UNION SELECT f1, f2
  5. FROM tabela ORDER BY f1) AS tabela2 WHERE (test1.f1-test2.f1)>0 ORDER BY tabela1.f1, (tabela1.f1-tabela2.f1) ASC) AS xxx;
  6. DROP TABLE tabela;
  7. ALTER TABLE nowa_table RENAME TO tabela;
To powinno zadziałać, ale jak już powtarzałem tylko na pgsql'u. Rzeby to przenieść na inną bazę trzeba wyeliminować DISTINCT ON, a ja jak na razie nie mam na to pomysłu. Aha, i w głównym selekcie wszystkie pola muszą! być wyliczone, nie można ich zastąpić *.
Potem możemy sobie zrobić sekwencje, ustawić jej currval na ostatnie id z tabeli i zmienić DEFAULT na nextval('nazwa_sekwencji').

AHA - I jeżeli będziesz próbował to transakcje włącz na wypadek jakbym się mylił.
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.