Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Mój pomysł: brak ID w tabeli
Forum PHP.pl > Forum > Bazy danych
Zajec
Potrzebuję stworzyć tabelę, która będzie kojarzyła ze sobą pozycje dwóch innych tabel:

1) Tabela "users" z id użytkownika i jego danymi
2) Tabela "hobby" z id hobby i nazwą hobby

Chcę, aby każdy użytkownik mógł sobie obrać kilka zdefiniowanych przeze mnie hobby. Tworzę więc tabelę z dwoma polami:
1) user_id
2) hobby_id

Teraz pytanie: Czy jest jakiś silny argument, aby dodawać pole id w tabeli łączącej? Zawsze mnie uczono, że id musi być i że ułatwia pracę, ale w tym przypadku szczerze mówiąc nie widzę zastosowania. Gdy user zmienia hobby po prostu kasuję jego dotychczasową listę hobby i tworzę jeszcze raz. Nie mam potrzeby odwoływania się do konkretnego wiersza tabeli łączącej.

Co więcej boję się, że przy częstej zmianie hobby, wartości jej pól "id" drastycznie urosną mimo ogólnie małej ilości wierszy. Dlatego głównie nie chciałbym dodawać pola "id".
envp
Oczywiście że id nie musi być. Id jest potrzebne tylko po to aby zidentyfikować wpis (np. gdy chcemy go usunąć) Najlepszym rozwiązaniem będzie chyba zrobienie tej tabeli jako dwóch kolum które dodatkowo są PK, co zapobiegnie zduplikowaniu wpisu...
NuLL
Zalezy w jakiej bazie - sa takie gdzie mozna zdefiniowac aby para wartosci byla unikalna smile.gif
Zajec
Dzięki za odpowiedź. Pominę w takim razie id.

(Baza: MySQL)

Cytat(envp @ 7.04.2007, 00:15:50 ) *
Najlepszym rozwiązaniem będzie chyba zrobienie tej tabeli jako dwóch kolum które dodatkowo są PK, co zapobiegnie zduplikowaniu wpisu...

PK:
Politechnika Poznańska
KB PK
Biblioteka PK
Polski Katalog
Panorama Kultur

Tyle zasugerowało Google. A co Ty miałeś na myśli? ;-)
maryaan
primary key....
Void(Null)
Nie wiem czy dobrze rozumuje, ale...

Jeśli chodzi ci o to aby każdy użytkownik miał w bazie więcej niż jedno hobby to niezbędna ci będzie tabela składająca relacje - jest to klasyczny przypadek encji wiele - do wielu, która nie ma prawa istnieć zgodnie z teorią relacyjnych baz danych. Możesz tak:

USERS

UserID | Name | Cośtam

HOBBYS

HobID | Hobby Name


HobbysOfUsers

AutoID | UID (to klucz UserID z tabeli USERS) | HID (analogiczny z HOBBYS)


pozdr.
dr_bonzo
Zajac: nie musisz robic IDka.

Cytat
Id jest potrzebne tylko po to aby zidentyfikować wpis (np. gdy chcemy go usunąć)


Patrz nizej: nie jest potrzebny
Cytat
Najlepszym rozwiązaniem będzie chyba zrobienie tej tabeli jako dwóch kolum które dodatkowo są PK, co zapobiegnie zduplikowaniu wpisu...

a szukasz rekordu jednoczesnie po user_id i hobby_id i masz jednoznacznie okreslony rekord
Darti
A ciekawi mnie przypadek, kiedy chcesz wybrać dwóch użytkowników z takimi samymi hobby (np żeby stworzyć 'wspólne koło zainteresowań). Jak wyglądałoby zapytanie w projekcie od @Zajec questionmark.gif
dr_bonzo
Tylko dwoch?
  1. SELECT h.name, u.name FROM hobbies h JOIN hobbies_users hu ON hu.hobby_id = h.id JOIN users u ON hu.user_ud = u.id LIMIT 2
Darti
@dr_bonzo coś Twoja metoda nie działa, zmontowałem na szybko takie dwie tabelki:
  1. CREATE TABLE `hobbies` (
  2. `user_id` int(5) NOT NULL DEFAULT '0',
  3. `hobby_id` int(5) NOT NULL DEFAULT '0'
  4. ) ENGINE=MyISAM DEFAULT CHARSET=latin1;
  5.  
  6. INSERT INTO `hobbies` VALUES (5, 8);
  7. INSERT INTO `hobbies` VALUES (1, 1);
  8. INSERT INTO `hobbies` VALUES (1, 2);
  9. INSERT INTO `hobbies` VALUES (1, 3);
  10. INSERT INTO `hobbies` VALUES (2, 1);
  11. INSERT INTO `hobbies` VALUES (2, 2);
  12. INSERT INTO `hobbies` VALUES (2, 3);
  13. INSERT INTO `hobbies` VALUES (3, 3);
  14. INSERT INTO `hobbies` VALUES (4, 9);
  15.  
  16. CREATE TABLE `users` (
  17. `user_id` int(5) NOT NULL DEFAULT '0',
  18. `name` varchar(20) NOT NULL DEFAULT ''
  19. ) ENGINE=MyISAM DEFAULT CHARSET=latin1;
  20.  
  21. INSERT INTO `users` VALUES (5, 'piaty');
  22. INSERT INTO `users` VALUES (1, 'pierwszy');
  23. INSERT INTO `users` VALUES (2, 'drugi');
  24. INSERT INTO `users` VALUES (3, 'trzeci');
  25. INSERT INTO `users` VALUES (4, 'czwarty');


i wmontowałem Twoje (podobne) zapytanie (pomińmy że miało być dwóch) :
  1. SELECT hu.name, u.name FROM hobbies h JOIN users hu ON h.hobby_id = hu.user_id JOIN users u ON h.user_id = u.user_id


Powinien wyświetlić tylko userów: pierwszy, drugi (bo mają zainteresowania 1,2,3) a wmieszał się tam jeszcze trzeci dziwnym trafem (bo ma tylko i wyłącznie zainteresowanie 3, ale się wkręcił na imprezkę i nie ma o czym gadać z pierwszym i drugim bo zeszli na tematy 1 lub 2 i trzeciemu grozi picie browara i rwanie lasek koło baru a chciał pogadać winksmiley.jpg ).
Sedziwoj
Darti co nagle to po diable, co prawda tabela z samymi hobby jak i user są niepotrzebne, bo ważne są id obu.
A wybranie dwóch osób, o takim samych hobby wcale nie jest takie proste. Ja chwilowo widzę tylko taką możliwość, że dla danego użytkownika szukamy innych o tych samych zainteresowaniach. Ponieważ jak widz chcesz pełne pokrycie zbiorów zainteresowań.

Wracając do tematu, id jest w tym przypadku zbędne, i ogólnie jak możemy określić unikalne pole lub ich kombinacji, tu UNIGUE(user_id,hobby_id), ale czasem jak jest albo nie możliwe wybranie unikalnych, lub dla prostoty użytkowania dodaje się id.
Dla prostoty: załóżmy że mamy tabele osób i każda ma PESEL (bo tak wynika z wymagań że jest zawsze podany) i można w ten sposób unikalnie identyfikować daną osobę, ale po pierwsze łączenie po polu pesel jest niewygodne i wytwarza o wiele więcej danych (bo każda powiązana musiała by mieć cały pesel), do tego udostępnia pesel osoby a takie dane są objęte ochroną, po drugie możliwe jest że ktoś wprowadzi błędny, a potem będzie chciał poprawić, jak już będzie w wielu miejscach, chyba każdy wie co by to znaczyło.
Tu mamy wewnętrzną identyfikację i prostą unikalność, do tego do tej tabeli nie podłączmy innych do unikalnego rekordu więc można (ale nie musimy) sobie darować pole id.
Darti
Tzn z mojego punktu widzenia ważna jest jedynie tabela 'hobbies', nie interesuje mnie to, jak nazywa się dany user (wystarczy mi ID).
Borykam się z tym problemem (braku unikalnej kolumny - nie mogę zmienić struktury tabel) od dosyć dawna.
Kombinowałem poprzez złączenie dwukrotnie jednej, tej samej tabeli (np pierwsza.hobby_id=druga.hobby_id) ale dawało mi w efekcie elementy 'niepełne' (tutaj niepełne zainteresowania trzeciej osoby).
Temat jest dla mnie niezwykle intrygujący ... po prostu nie lubię wiedzieć że czegoś nie wiem smile.gif A nie wiem jak unikatowo wybrać z takiej tabeli (hobbies) osoby o takich samych zainteresowaniach.
Pomóżcie proszę zapytaniem SQL ....
Sedziwoj
Darti problem nie jest jak mi się wydaje banalny, bo jeśli chcesz wybrać osoby o danym hobby lub nawet kilku to nie jest problem.
Jednak gdy chcesz wybrać osoby o takich samych zainteresowaniach to pamiętaj że każdy może mieć inną długość listy hobby więc dla każdej osoby wybierasz takie które mają taką samą, takich osób może być kilka.
Więc wybierasz osobę i jej zainteresowania np.:
user_id|hobby_id
1|1
1|2
1|3
potem szukasz osoby która ma te zainteresowania, ale tu tracę pomysł jak...
albo mam błędne założenia od początku. Ale wynikiem końcowym będzie tablica o dwóch polach user_id gdzie obaj użytkownicy mają te same hobby (przy czym będzie coś w stylu 1|2 i 2|1 z powodu że to jest relacja dwu kierunkowa)

Mam małe doświadczenie w tworzeniu zapytań i jeszcze nie czytałem żadnej porządnej książki o tym :|

Coś wykombinowałem, działa, ale optymalności to pewnie ani ciut, ciut nie ma:
  1. SELECT `nalezy`.`u_id`,`zawiera`.`u_id` FROM (SELECT `max`.`u_id`,`sum`.`t_u` FROM (SELECT `u2`.`u_id`,count(*) AS `x` FROM `ush` AS `u2` GROUP BY `u2`.`u_id`) AS `max`
  2. JOIN (SELECT `ush`.`u_id` AS `f_u`,`u`.`u_id` AS `t_u`, COUNT(`u`.`h_id`) AS `ile` FROM `ush` LEFT JOIN `ush` AS `u` ON `u`.`h_id`=`ush`.`h_id` GROUP BY `ush`.`u_id`,`u`.`u_id`) AS `sum`
  3. ON (`max`.`x`=`sum`.`ile` AND `max`.`u_id`=`sum`.`f_u`)) AS `nalezy`
  4. LEFT JOIN (SELECT `max`.`u_id`,`sum`.`t_u` FROM (SELECT `u2`.`u_id`,count(*) AS `x` FROM `ush` AS `u2` GROUP BY `u2`.`u_id`) AS `max`
  5. JOIN (SELECT `ush`.`u_id` AS `f_u`,`u`.`u_id` AS `t_u`, COUNT(`u`.`h_id`) AS `ile` FROM `ush` LEFT JOIN `ush` AS `u` ON `u`.`h_id`=`ush`.`h_id` GROUP BY `ush`.`u_id`,`u`.`u_id`) AS `sum`
  6. ON (`max`.`x`=`sum`.`ile` AND `max`.`u_id`=`sum`.`f_u`)) AS `zawiera`
  7. ON (`nalezy`.`t_u`=`zawiera`.`u_id` AND `nalezy`.`u_id`=`zawiera`.`t_u`)
  8. WHERE `nalezy`.`u_id`<`zawiera`.`u_id`


proste nieprawdaż?

i i tabelka taka:
  1. CREATE TABLE `ush` (
  2. `u_id` int(11) NOT NULL,
  3. `h_id` int(11) NOT NULL,
  4. PRIMARY KEY (`u_id`,`h_id`)
  5. )


jak macie lepsze pomysły piszcie.

EDIT próba aby trochę połamało zapytanie
Darti
@Sedziwoj jesteś geniuszem w tym temacie smile.gif
działa doskonale, Dzięki wielkie smile.gif
dr_bonzo
1. Darti: sorry za blad; zle zrozumialem twoja prosbe (mialem wszystkich wypisac userow z jednym, ustalonym hobby -- zapomnialem o WHERE

2. Sedziwoj: WOW, jak ty sie w tym nie pogubiles smile.gif


3. [chyba zaraz dopisze]
edit: albo i nie bedzie, nie mam teraz czasu
Sedziwoj
Cytat(dr_bonzo @ 17.05.2007, 11:33:43 ) *
2. Sedziwoj: WOW, jak ty sie w tym nie pogubiles smile.gif


Tylko czy nie można lepiej tego zrobić, to jedynie mnie martwi...

A co do optymalizacji to po prostu stworzenie tymczasowej tabeli, bo w sumie łączem dwie takie same (LEFT JOIN) więc po co dwa razy używać skomplikowanego zapytania.

I nadal czekam na konstruktywną krytykę, bo może da się coś poprawić, albo ma metoda od założenia była błędna...
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.