Wpis z mikrobloga

#programowanie #oracle #sql

Chce napisać zapytanie które dokona edycji wartości w jednej tabeli na podstawie wartości w drugiej. Ma to wyglądać w ten sposób, że chce zmienić ocenę w tabeli zaliczenia na podstawie nazwy przedmiotu z tabeli przedmioty (w zaliczeniach jest klucz obcy na id przedmiotu). Próbuję to zrobić w ten sposób:

UPDATE (SELECT przedmiot.nazwa, zaliczenie.ocena
FROM przedmiot, zaliczenie
WHERE przedmiot.id_przed=zaliczenie.id_przed
AND przedmiot.nazwa='Fizyka'
AND zaliczenie.ocena=2)
SET ocena=3, zaliczenie.data=(SELECT sysdate FROM dual);

ale dostaje SQL Error: ORA-00904. Mam pewności, że nazwy tabeli itp są poprawne. Może ktoś pomóc to rozgryźć?
  • 19
@mikra25: update zaliczenie
set ocena=3, zaliczenie.data=current_date
where zaliczenie.PK in
(SELECT zaliczenie.PK
FROM przedmiot, zaliczenie
WHERE przedmiot.id_przed=zaliczenie.id_przed
AND przedmiot.nazwa='Fizyka'
AND zaliczenie.ocena=2)

Za PK wstaw klucz główny tabeli zaleczenie
@oko_strusia: Właśnie chciałem kombinować w ten sposób tylko, że tabela zaliczenia jest zbudowana w specyficzny sposób, tak jakby bez klucza głównego

id_przed NUMBER(3,0),
nr_albumu NUMBER(3,0),
termin VARCHAR2(15),
data DATE,
ocena NUMBER(1),
CONSTRAINT zaliczenie_01 PRIMARY KEY (id_przed,nr_albumu,termin),
CONSTRAINT zaliczenie_02 FOREIGN KEY (nr_albumu) REFERENCES student (nr_albumu),
CONSTRAINT zaliczenie_03 FOREIGN KEY (id_przed) REFERENCES przedmiot (id_przed),
CONSTRAINT zaliczenie_04 CHECK (ocena IN (2,3,4,5)),
CONSTRAINT zaliczenie_05 CHECK (termin IN ('1','2','3','KOMIS'))
@mikra25: Na dzień dobry masz złą składnie, więc się wywali...
Poprawna kolejność powinna być jak wyżej:
UPDATE SET FROM WHERE AND AND

Na pewno początek powinien być taki:
UPDATE zaliczenie z
SET z.ocena=3, z.data = SYSDATE

i tutaj nie do końca ogarniam, ale domyślam się że coś takiego

WHERE z.idprzed IN
(
SELECT id
przed FROM przedmiot WHERE nazwa = 'Fizyka'
)
AND z.ocena = 2;

Ogólnie, to poczytaj jak
@mikra25: Własnie doczytałem jeszcze
W Oracle w UPDATE nie masz w ogóle FROM

Składnia jest taka
UPDATE [tabela]
SET [wartości, które zmieniasz]
WHERE [warunki]
@mpisz: Robiłem tak na początku to mi się rzucał że nazwa tabeli przedmiot jest niepoprawna lub tabela nie istnieje. Myślałem to zrobić po prostu
UPDATE zaliczenie
SET ocena=3
WHERE zaliczenie.idprzed=przedmiot.idprzed
AND przedmiot.nazwa='Fizyka'
i wydaje mi się że to powinno działać ale nie działa
To Ci nie może zadziałać, bo nie podajesz nigdzie pobrania z tabeli przedmiot.
Ten update co dałem wyżej nie działa? Jak ORA sypie?

Bo jak masz wszystko ok, to to na 100% powinno zadziałać (mogłem nazwy kolumn pozmieniać)

UPDATE zaliczenie z
SET z.ocena=3, z.data = SYSDATE
WHERE z.id_przed IN
(
SELECT id_przed FROM przedmiot WHERE nazwa = "Fizyka"
)
AND z.ocena = 2;

Rozumiem, że chcesz zaktualizować w tabeli zaliczenie oceny dla
@oko_strusia: Nie rób złączeń w ten sposób. W tym przypadku najpierw wykonuje się FROM i robi wielki iloczyn kartezjański a potem dopiero WHERE go filtruje. Jak podasz we FROM tylko tabelę nadrzędną i dodasz JOIN XXX ON A=B to tego unikniesz.
@SpioncyPotwur: Z tego co mi wiadomo to optymalizator przebuduje to i tak na taką składnię, żeby kartezjana nie robić. Ale ogólnie uwaga względnie słuszna. Nie wiem jak w innych DMBS. W Oraclu możesz sobie zobaczc plan zapytania jednego i drugiego zapytania i powinny być takie same.
@oko_strusia: Prawda, ale po pierwsze - poleganie na automatycznych optymalizacjach nie do końca jest ok a po drugie o ile Oracle jest w optymalizacjach świetny to przenosząc kod na inny system, nie możemy mieć pewności, że to będzie działać tak samo.
@mikra25: Update opiera się na jednej tabeli, bo aktualizujesz dane tylko w tabeli zaliczenie.
Warunki, według których wybierasz są zależne od innych tabel.:)
@mikra25: 1) alias "zaliczenie" nie sięga poza nawias
2) próbujesz zrobić "update z selekta". Oracle od wersji 11 dopuszcza takie rzeczy ale jeśli select jest z 1 tabeli. Nie używać
3) przepisz to aby zrobić samą instrukcję update a nie update z selecta, np:
UPDATE zaliczenie
SET ocena = 3, data = SYSDATE
WHERE zaliczenie.idprzed IN (SELECT przedmiot.idprzed
FROM przedmiot
WHERE przedmiot.nazwa = 'Fizyka')
AND zaliczenie.ocena = 2