[create table] tab bez duplikatów

Odpowiedz Nowy wątek
kasiaKasia
2010-11-19 13:17
kasiaKasia
0

witam serdecznie,
od kilku dni borykam się z problemem dotyczącym zbudowania tab. która nie przechowuje duplikatów. Chciałabym stworzyć taką tab. która dla konkretnego pracownika

employess_id

pracującego w dziale departments_id

 nie zapisze gdy już pracował w jakimś dniu, który znajduję się w przedziale czasowym który jest już zapisany w bazie danych. Dla wyjaśnienia, np:
N1(pracownik)
           v_begin           v_end
           12.01.2010      18.01.2010
N2(ten sam pracownik , ale chcemy go wprowadzić do bazy)
           v_begin           v_end
           13.01.2010      15.01.2010

buduje sprawdzanie (znajduje się w kodzie)
          12.01.2010 < 15.01.2010
          13.01.2010 < 18.01.2010 --tu się 2 porównania zgadzają wiec , przedział  [13.01.2010 ,15.01.2010 ]nie powinien zostać zapisany do bazy danych 

Kod przedstawia się następująco:
```sql
create table time_work_test (
  id NUMBER(4) NOT NULL PRIMARY KEY,
  employess_id NUMBER(4),
  departments_id NUMBER(4),
  v_begin TIMESTAMP,
  v_end  TIMESTAMP,
  t_start TIMESTAMP,
  t_stop TIMESTAMP)
CHECK (NOT EXISTS (SELECT N1.id 
                     FROM time_work_test N1 WHERE 1 <=  (SELECT COUNT(N2.employess_id)
                        FROM time_work_test N2
                        WHERE N1.employess_id = N2.employess_id
                        AND N1.departments_id = N2.departments_id
                        AND N1.v_begin <= N2.v_end
                        AND N2.v_begin <= N1.v_end)));

zwraca mi następujący komunikat błędu:

ORA-00922: missing or invalid option

Uprzejmie proszę o jakąś wskazówkę....?

Pozostało 580 znaków

2010-11-19 13:28
Administrator

Rejestracja: 18 lat temu

Ostatnio: 8 godzin temu

0
SET @result = (SELECT COUNT(*) FROM time_work_test WHERE employees_id = /* tutaj ID pracownika */ AND /* tutaj data rozpoczecia pracy */ BETWEEN v_begin AND v_end);
IF @result = 0 THEN /* robimy INSERT wstawiajac do bazy.. */
END IF;

Pisane z palca. Nie wiem z jakiej bazy korzystasz, tutaj podsuwam tylko idee ;) Tzn. sprawdzenie warunkiem IF czy podobny rekord juz istnieje, a jezeli nie - wstawienie go.

Pozostało 580 znaków

2010-11-19 14:17

Rejestracja: 11 lat temu

Ostatnio: 1 tydzień temu

0

1-czy w check można w ogóle dawać zapytania? sprawdz robiąc najprostszy warunek np:
CHECK (NOT EXISTS (SELECT N1.id
FROM time_work_test N1 WHERE employess_id = N1.employess_id));

2- po co Ci n1 i n2? z opisu na http://techonthenet.com/oracle/check.php wynika, że do nowej wartości odwołujesz się przez nazwę kolumny u ciebie np przez samo employess_id bez aliasu.
coś takiego:
CHECK (NOT EXISTS (SELECT N1.id
FROM time_work_test N1 WHERE v_begin <= N1.v_end //tu reszta warunków))

  1. jak się nie da, to użyj triggera on insert

ps piszę posta, klikam wyślij, a on się nie publikuje, i musze pisać drugi raz-masakra

edytowany 2x, ostatnio: void-tec, 2010-11-19 14:19

Pozostało 580 znaków

kasiaKasia
2010-11-22 16:03
kasiaKasia
0

Witam serdecznie,

chciałabym przeprosić ze dopiero teraz odpisuje, ale straciłam dostęp do Internetu :( Jestem teraz w kawiarence.

Najbardziej mi zależy na stworzeniu tabeli od razu blokującej dodawanie, ale warto się tez nauczyć tworząc procedurę, która blokuje dodawanie rekordu.
Próbowałam w następujący sposób:

set serveroutput on
CREATE OR REPLACE PROCEDURE d_time_work (x_id time_work_test.id%TYPE,
                            x_employess_id time_work_test.employess_id%TYPE,    
                            x_departments_name time_work_test.departments_name%TYPE,
                            x_begin time_work_test.v_begin%TYPE,
                            x_end time_work_test.v_end%TYPE, 
                            x_start time_work_test.t_start%TYPE,
                            x_stop time_work_test.t_stop%TYPE ) IS 
err EXCEPTION;
wynik NUMBER(3);
p_employess_id time_work_test.employess_id%TYPE;
p_departments_name time_work_test.departments_name%TYPE;
p_begin time_work_test.v_begin%TYPE;
p_end time_work_test.v_end%TYPE; 
   BEGIN 
    SELECT COUNT(*) INTO wynik FROM time_work_test 
    WHERE x_employess_id = p_employess_id
    AND x_departments_name = p_departments_name
    AND p_begin between p_begin AND p_end;  

    IF (x_employess_id=p_employess_id AND x_departments_name=p_departments_name AND wynik = 0 ) THEN    
INSERT INTO time_work_test VALUES(x_id, x_employess_id, x_departments_name, x_begin,x_end,x_start,x_stop);
dbms_output.put_line('dodano ponieważ pracownik nie był w tym czasie w pracy'|| wynik);
    ELSE
        RAISE err;  
    END IF;
     EXCEPTION 
     WHEN err THEN 
         dbms_output.put_line('pracownik był w tym terminie'|| wynik);
     WHEN no_data_found THEN 
       dbms_output.put_line('nie poprawne dane w rekordzie'|| wynik);
   END;

Jednak źle zbudowałam żel zapytanie select .. W kodzie procedury cały czas zawraca mi 0, nawet jeśli pracownik w tym czasie był w pracy.
Próbowałam korzystać również z INNER JOIN ... ale bez rezultatów.

Jeśli ktoś mam chcę spojrzeć i dać mi jakość wskazówkę jak to poprawić byłabym bardzo wdzięczna ...?

Pozostało 580 znaków

2010-11-23 15:23

Rejestracja: 11 lat temu

Ostatnio: 1 tydzień temu

0

literówka o tu:
AND p_begin BETWEEN p_begin AND p_end;
zamien na x_begin

Pozostało 580 znaków

kasiaKasia
2010-11-26 23:22
kasiaKasia
0

Witam,

przepraszam ponownie, ale nadal mam bardzo utrudniony dostęp do internetu <płacze>

Próbowałam na wiele sposobów np:

SELECT COUNT(*) INTO wynik FROM time_work_test 
    WHERE x_employess_id = p_employess_id
    AND x_departments_name = p_departments_name
    AND x_begin between x_begin AND x_end;

SELECT COUNT(*) INTO wynik FROM time_work_test t
    INNER JOIN employess e on x_employess_id = p_employess_id
    INNER JOIN departments d on x_departments_name = p_departments_name
    WHERE x_begin between x_begin AND x_end;


    SELECT COUNT(p_id) INTO wynik FROM time_work_test t
    INNER JOIN employess e on x_employess_id = p_employess_id
    INNER JOIN departments d on x_departments_name = p_departments_name
        WHERE x_begin <= p_end
        AND p_begin <= x_end;

    SELECT COUNT(t.employess_id) INTO wynik FROM time_work_test t
    INNER JOIN employess e on x_employess_id = e.id
    INNER JOIN departments d on x_departments_name = d.name
        WHERE x_begin <= p_end
        AND p_begin <= x_end;

SELECT COUNT(*) INTO wynik FROM time_work_test t
    INNER JOIN employess e on x_employess_id = e.id
    INNER JOIN departments d on x_departments_name = d.name
        WHERE x_begin <= p_end
        AND p_begin <= x_end;

Niestety te zmiany nie pomogły, nadal mi dodaje pracownika. Nawet jeśli był w tym czasie w pracy .

Proszę miło, o jakąś wskazówkę i wyrozumienie dla mnie z powodu mojego braku internetu :(

Pozostało 580 znaków

2010-11-27 23:00

Rejestracja: 10 lat temu

Ostatnio: 8 lat temu

0

Na początek odniosę się do Twoich prób check w create table. Nie da się tego tak wykonać ponieważ:
1) Nie możesz stosować podzapytań w klauzuli check
2) Możesz odwoływać się wyłącznie do kolumn z tabeli na której zakładasz check

Wydaje mi się, że ograniczenie należy wykonać na poziomie procedury dodającej dane.
Czy dalej masz z nią problemy?

Pozostało 580 znaków

kasiaKasia
2010-11-28 00:55
kasiaKasia
0

Tworząc create table .. odwołuje się do kolumn z tabeli na której chce utworzyć ograniczenie. Te pola

 employess_id,
 departments_id ,
  v_begin,
  v_end  ,
  t_start ,
  t_stop  

sa przecież w tabeli

time_work_test

, na którą chce założyć ograniczenie:

CHECK (NOT EXISTS (SELECT N1.id
                     FROM time_work_test N1 WHERE 1 <=  (SELECT COUNT(N2.employess_id)
                                                FROM time_work_test N2
                                                WHERE N1.employess_id = N2.employess_id
                                                AND N1.departments_id = N2.departments_id
                                                AND N1.v_begin <= N2.v_end
                                                AND N2.v_begin <= N1.v_end)));

nie chciałabym, aby dany pracownik ,mógł znaleźć się w tej tabeli kilka razy w tym czasie gdy już był w pracy.

Tak masz racje chyba najlepszym sposobem, będzie utworzenie procedury :)

ale nie wiem jak zbudować zapytanie select ... aby nie dodawało pracownika, który ma takie dane np

employess_id    = 1
departments_id  = 2
v_begin         = 12-12-2010
v_end           = 15-12-2010

i teraz np jak bym chciała wstawić takie dane :

employess_id    = 1
departments_id  = 2
v_begin         = 13-12-2010
v_end           = 14-12-2010

to powinien się wyświetlić komunikat o błędzie, że pracownik był w tym czasie w pracy......?

Pozostało 580 znaków

2010-11-28 10:23

Rejestracja: 10 lat temu

Ostatnio: 8 lat temu

0

1) ale ograniczenie chcesz założyć tworząc podzapytanie - select - tego nie wolno w Oracle

2) nie jestem do końca pewien jakie masz wymagania dotyczące warunków nachodzenia na siebie zakresów dat - dalatego przykład na szybko:

create table temp(
    emp_id number
    dep_id number
    start date
    end date
);

jeśli sprawdzamy czy nowy przedział ma część wspólną z istniejącym:

select count(*)
from temp t 
where
        t.emp_id = v_emp_id
    and t.dep_id = v_dep_id
    and (v_start between t.start and t.end or v_end between t.start and t.end)

jeśli spawdzamy czy nowy przedział zawiera się w już istniejącytym to:

...
    and (v_start between t.start and t.end and v_end between t.start and t.end)
edytowany 1x, ostatnio: kshysieq, 2010-11-28 10:24

Pozostało 580 znaków

kasiaKasia
2010-11-28 14:33
kasiaKasia
0

DZIĘKUJE SERDECZNIE DZIAŁA :>

zamieszczam kod może komuś się przyda:

CREATE OR REPLACE PROCEDURE d_time_work (x_id time_work_test.id%TYPE,
                            x_employess_id time_work_test.employess_id%TYPE,    
                            x_departments_name time_work_test.departments_name%TYPE,
                            x_begin time_work_test.v_begin%TYPE,
                            x_end time_work_test.v_end%TYPE, 
                            x_start time_work_test.t_start%TYPE,
                            x_stop time_work_test.t_stop%TYPE ) IS 
err EXCEPTION;
wynik NUMBER(3);

   BEGIN 
    SELECT COUNT(*) INTO wynik FROM time_work_test 
WHERE  employess_id = x_employess_id 
AND departments_name = x_departments_name 
        AND (x_begin BETWEEN v_begin AND v_end OR x_end BETWEEN v_begin AND v_end);

    IF ( wynik = 0 ) THEN    
INSERT INTO time_work_test VALUES(x_id, x_employess_id, x_departments_name, x_begin,x_end,x_start,x_stop);
dbms_output.put_line('dodano ponieważ pracownik nie był w tym czasie w pracy ' );
    ELSE 
        RAISE err;  
    END IF;
     EXCEPTION 
     WHEN err THEN 
         dbms_output.put_line('pracownik był w tym terminie'|| wynik);
     WHEN no_data_found THEN 
       dbms_output.put_line('nie poprawne dane w rekordzie'|| wynik);
   END;
/
show err

tabela przedstawia się w następujący sposób:

create table time_work_test (
  id NUMBER(4) NOT NULL PRIMARY KEY,
  employess_id NUMBER(4),
  departments_name VARCHAR2(30),
  v_begin TIMESTAMP,
  v_end  TIMESTAMP,
  t_start TIMESTAMP,
  t_stop TIMESTAMP
  );

ALTER TABLE time_work_test
ADD FOREIGN KEY (employess_id)
REFERENCES employess(id);

ALTER TABLE time_work_test
ADD FOREIGN KEY (departments_name)
REFERENCES departments(name);

Pozostało 580 znaków

Odpowiedz

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