2009-01-10 7 views
67

Mam dwie tabele w mojej bazy danych:PHP i MYSQL: Jak rozwiązać niejednoznaczne nazwy kolumn w operacji JOIN?

NEWS ('id' - identyfikator wiadomości, 'użytkownik' - identyfikator użytkownika autora)

użytkowników ('id' - id użytkownika)

chcę zrobić SELECT * FROM news JOIN users ON news.user = user.id, teraz kiedy się wyniki w PHP to coś jak:

$row = mysql_fetch_array($result) i uzyskać nazwy kolumny $row['column-name'] ... jak mogę uzyskać identyfikator aktualności i identyfikator użytkownika, posiadającego ta sama nazwa kolumny?

AKTUALIZACJA: Dziękuję wszystkim za szybkie odpowiedzi. Aliasy wydają się najlepszym rozwiązaniem.

Odpowiedz

109

Można ustawić aliasy kolumn, które są składzie:

$query = 'SELECT news.id AS newsId, user.id AS userId, [OTHER FIELDS HERE] FROM news JOIN users ON news.user = user.id' 
+1

Ta odpowiedź spowodowała, że ​​odpowiedzi na http://stackoverflow.com/questions/9233387/sql-should-i-used-a-join pracę dla mnie, dziękuję! – AVProgrammer

+2

Główną wadą tego podejścia jest to, że w przeciwieństwie do 'SELECT *' zapytanie jest ściśle powiązane ze strukturą tabeli. Oznacza to, że po dodaniu/usunięciu/zmianie nazwy kolumn w schemacie należy odpowiednio zmienić zapytanie. –

+3

@RonInbar. 'SELECT *' to koszmar utrzymania w dużych systemach. Sugerujesz, że dodanie kolumny jest proste i nie wymaga żadnych zmian w SQL, jeśli używasz 'SELECT *', ale tak nie jest, jak w omawianym tu przypadku aliasingu. Może również nadać niepotrzebny wpływ na wydajność, jeśli nowe pole jest duże. Może również złamać kontrolki po stronie klienta, które oczekują określonej liczby lub pól. Mogę iść dalej, ale korzyści z "SELECT *" bardzo szybko znikają, gdy zrozumiesz, jaki wpływ ma to na łatwość utrzymania i wydajność. –

38

Można użyć indeksów liczbowych ($row[0]) lub lepiej wykorzystywać AS w MySQL:

SELECT *, user.id AS user_id FROM ...

+12

Należy również zauważyć, że jeśli używasz wildwarcd '*', musi to być pierwsza z klauzuli select. NOT: 'SELECT id_użytkownika, * ...' – Anders

+1

Prawda, ale zawsze możesz zrobić: "SELECT user.id AS user_id, user. * FROM ...' jeśli kolejność ma znaczenie. – Cyrille

8

Możesz zrobić coś w rodzaju:

SELECT news.id as news_id, user.id as user_id .... 

A następnie $row['news_id'] będzie identyfikatorem aktualności, a $row['user_id'] będzie identyfikatorem użytkownika

1

Jeśli nie masz ochoty na rozkręcanie, możesz również po prostu przedrostać nazwy tablicames.

W ten sposób można lepiej zautomatyzować generowanie zapytań. Ponadto, jest to najlepsze praktyki, aby nie używać select * (to jest oczywiście wolniejsza niż tylko wybranie pola, które potrzebę Ponadto tylko jawnie nazwa pola, które chcesz mieć.

SELECT 
    news.id, news.title, news.author, news.posted, 
    users.id, users.name, users.registered 
FROM 
    news 
LEFT JOIN 
    users 
ON 
    news.user = user.id 
+0

Jest z tym problem. PHP usunie prefiks. więc jeśli pobierzesz wynik, nie możesz zrobić '$ row ['new.id']' .. jakiegokolwiek rozwiązania dla tego? – GameDeveloper

19

Właśnie zorientowaliśmy na zewnątrz. to chyba złą praktyką, ale pracował dla mnie w tej sprawie.

Jestem jednym z tych leniwych, którzy nie chcą alias lub wypisać każdą nazwę kolumny z przedrostkiem tabeli.

Ty można wybrać wszystkie kolumny z określonej tabeli, używając table_name.* w instrukcji select.

Gdy już duplikowane nazwy kolumn, będzie mysql nadpisać od pierwszego do ostatniego. Dane z pierwszej zduplikowanej nazwy kolumny zostaną nadpisane, gdy ponownie napotkają tę nazwę kolumny. Tak więc nazwa zduplikowanej kolumny, która pojawia się w ostatnim, wygrywa.

Jeśli jestem łączenia 3 tabel, z których każda zawiera powtórzoną nazwą kolumny, kolejność tabel w select określi jakie dane Dostaję dla duplikatu kolumnie.

przykład:

SELECT table1.* , table2.* , table3.* FROM table1 LEFT JOIN table2 ON table1.dup = table2.dup LEFT JOIN table3 ON table2.dup = table3.dup; 

W powyższym przykładzie wartość dup uzyskać będzie od table3.

Co jeśli chcę, aby dup była wartością z table1?

Potem muszę to zrobić:

SELECT table3.* , table2.* , table1.* FROM table1 LEFT JOIN table2 ON table1.dup = table2.dup LEFT JOIN table3 ON table2.dup = table3.dup; 

Teraz table1 jest ostatni, więc wartość dup będzie wartość od tabela1.

mam wartość chciałem dla dup bez konieczności pisania na każdą kolumnę pojedynczą niecodzienna, a ja wciąż dostać wszystkie kolumny pracować. Yay!

Wiem, że wartość dup powinna być taka sama we wszystkich 3 tabelach, ale co, jeśli table3 nie ma pasującej wartości dla dup? Wtedy dup byłaby pusta w pierwszym przykładzie, a to byłby bummer.

+2

Opieranie się na nieudokumentowanym zamawianiu, które działa teraz dla ciebie i nie spowoduje żadnych błędów, jeśli implementacja bazy danych zmieni się na AWFUL. –

+2

Hack zamawiania jest przerażający, ale +1 dla możliwości wybrania z 'table. *' Tak, że mogę zrobić 'SELECT table1. *, Table2.this_one_column_need FROM table1 INNER JOIN table2 ON ...'. – tobek

2

Miałem ten sam problem z tabelami dynamicznymi. (Tabele, w których zakłada się, że id ma możliwość dołączenia, ale bez żadnego założenia dla pozostałych pól.) W tym przypadku nie znasz aliasów przed ręką.

W takich przypadkach można najpierw uzyskać nazwy kolumn tabeli dla wszystkich tabel dynamicznych:

$tblFields = array_keys($zendDbInstance->describeTable($tableName)); 

Gdzie $ zendDbInstance jest instancją Zend_Db lub można użyć jednej z funkcji, żeby nie polegać na Zend php pdo: get the columns name of a table

Wtedy dla wszystkich tabel dynamicznych można uzyskać aliasy i użyć $ tableName * dla tych nie trzeba aliasy.

$aliases = ""; 
foreach($tblKeys as $field) 
    $aliases .= $tableName . '.' . $field . ' AS ' . $tableName . '_' . $field . ',' ; 
$aliases = trim(',', $aliases); 

Y możesz zawinąć cały proces w jedną ogólną funkcję i mieć czystszy kod lub uzyskać więcej leniwego, jeśli chcesz :)

8

@Jason. Masz rację, z wyjątkiem tego, że php jest winowajcą, a nie mysql. Jeśli umieścisz swój JOIN w Mysql Workbench, otrzymasz trzy kolumny o dokładnie takiej samej nazwie (po jednym dla każdej tabeli), ale nie z tymi samymi danymi (niektóre będą null, jeśli ta tabela nie pasuje do JOIN).

W php jeśli użyjesz MYSQL_NUM w mysql_fetch_array(), otrzymasz wszystkie kolumny. Problem występuje, gdy używasz mysql_fetch_array() z MYSQL_ASSOC. Następnie wewnątrz tej funkcji, php jest budowanie wartości zwracanej tak:

$row['dup'] = [value from table1] 

a później ...

$row['dup'] = [value from table2] 

...

$row['dup'] = [value from table3] 

Więc dostaniesz tylko wartość z table3. Problem polega na tym, że zestaw wyników z mysql może zawierać kolumny o tej samej nazwie, ale tablice asocjacyjne w php nie pozwalają na duplikowanie kluczy w tablicach. Gdy dane są zapisywane w tablicach asocjacyjnych, w php niektóre informacje są cicho tracone ...

9

Kolejna porada: jeśli chcesz mieć czystszy kod PHP, możesz utworzyć WIDOK w bazie danych, np.

Na przykład:

CREATE VIEW view_news AS 
SELECT 
    news.id news_id, 
    user.id user_id, 
    user.name user_name, 
    [ OTHER FIELDS ] 
FROM news, users 
WHERE news.user_id = user.id; 

W PHP:

$sql = "SELECT * FROM view_news"; 
-1

Istnieją dwa podejścia:

1. pomocą aliasów; w tej metodzie podajesz nowe unikalne nazwy (ALIAS) do różnych kolumn, a następnie używasz ich w pobieraniu PHP.

np.

SQL $ sql = SELECT student_id FEES_LINK, student_class CLASS_LINK z students_fee_tbl LEFT JOIN student_class_tbl NA students_fee_tbl.student_id = student_class_tbl.student_id

PHP $ query = mysql_fetch_assoc ($ sql); // jeśli przy użyciu starego podejścia

$ query = PDO->fetchAll(); // nie dokładna składnia ale to jest obecne podejście

foreach($query as $q){ 
echo $q['FEES_LINK']; 
} 

2.

Używanie pozycji miejsca lub wskaźnika kolumny zestawu wyników; w tym, pozycje tablicowe są używane do odniesienia do zduplikowanych nazw kolumn. Ponieważ pojawiają się one w różnych pozycjach, numery indeksu, które będą używane, będą zawsze unikalne. Jednak numery pozycjonowania indeksu zaczynają się od 0.

np.

$ sql = SELECT student_id, student_class z students_fee_tbl LEFT JOIN student_class_tbl NA students_fee_tbl.student_id = student_class_tbl.student_id

PHP

$ query = mysql_fetch_assoc ($ sql); // jeśli używasz starego podejście

$ query = PDO-> fetchAll(); // nie dokładna składnia ale to jest obecne podejście

foreach($query as $q){ 

    echo $q[0]; 

} 

dwie prace.

Mam nadzieję, że to pomaga. :)