it-swarm.com.ru

PHP & MYSQL: как разрешить неоднозначные имена столбцов в операции JOIN?

У меня есть две таблицы в моей базе данных:

NEWS ('id' - идентификатор новости, 'user' - идентификатор пользователя автора)

USERS ('id' - идентификатор пользователя)

Я хочу создать SELECT * FROM news JOIN users ON news.user = user.id, теперь, когда я получаю результаты в PHP, это что-то вроде:

$row = mysql_fetch_array($result) и получать имена столбцов по $row['column-name']... как получить идентификатор новости и идентификатор пользователя с одинаковым именем столбца?

ОБНОВЛЕНИЕ: Спасибо всем за быстрые ответы. Псевдонимы кажутся лучшим решением.

71
Dan Burzo

Вы можете установить псевдонимы для столбцов, которые вы выбираете:

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

Вы можете использовать числовые индексы ($row[0]) или, что лучше, использовать AS в MySQL:

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

40
Greg

Я только что понял это. Вероятно, это плохая практика, но в этом случае она сработала.

Я один из ленивых людей, которые не хотят создавать псевдонимы или записывать каждое имя столбца с префиксом таблицы.

Вы можете выбрать все столбцы из определенной таблицы, используя table_name.* в своем операторе выбора.

Если у вас есть дублированные имена столбцов, mysql будет перезаписывать от первого до последнего. Данные из первого дублированного имени столбца будут перезаписаны при повторном обнаружении этого имени столбца. Таким образом, повторяющееся имя столбца, которое приходит в последнюю очередь, выигрывает.

Если я присоединяюсь к 3 таблицам, каждая из которых содержит дублированное имя столбца, порядок таблиц в операторе выбора будет определять, какие данные я получаю для дублирующего столбца.

Пример:

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

В приведенном выше примере значение dup, которое я получу, будет от table3.

Что если я хочу, чтобы dup было значением из table1?

Тогда мне нужно сделать это:

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

Теперь table1 стоит последним, поэтому значение dup будет значением из таблицы1.

Я получил желаемое значение для dup без необходимости записывать каждый отдельный столбец, и я все еще заставляю работать со всеми столбцами. Ура!

Я знаю, что значение dup должно быть одинаковым во всех 3 таблицах, но что если table3 не имеет подходящего значения для dup? Тогда dup будет пустым в первом примере, и это будет облом.

21
Eab

Другой совет: если вы хотите иметь более чистый PHP код, вы можете создать VIEW в базе данных, например,.

Например:

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;

В PHP:

$sql = "SELECT * FROM view_news";
9
Dirk

@Jason. Вы правы, за исключением того, что php виновник, а не mysql. Если вы поместите свое JOIN в Mysql Workbench, вы получите три столбца с одинаковым именем (по одному для каждой таблицы), но не с одинаковыми данными (некоторые будут null, если эта таблица не соответствует JOIN).

В php, если вы используете MYSQL_NUM в mysql_fetch_array(), вы получите все столбцы. Проблема в том, что вы используете mysql_fetch_array() с MYSQL_ASSOC. Затем внутри этой функции php создает возвращаемое значение следующим образом:

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

и позже ...

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

...

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

Таким образом, вы получите только значение из таблицы 3. Проблема в том, что результирующий набор из mysql может содержать столбцы с одинаковыми именами, но ассоциативные массивы в php не допускают дублирования ключей в массивах. Когда данные сохраняются в ассоциативных массивах, в php, некоторая информация молча теряется ...

8
GoTo

Вы можете сделать что-то вроде

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

И тогда $row['news_id'] будет идентификатором новостей, а $row['user_id'] будет идентификатором пользователя

8
Paolo Bergantino

У меня была такая же проблема с динамическими таблицами. (Таблицы, которые, как предполагается, имеют идентификатор для возможности присоединения, но без каких-либо допущений для остальных полей.) В этом случае вы не знаете псевдонимы заранее.

В таких случаях вы можете сначала получить имена столбцов таблицы для всех динамических таблиц:

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

Где $ zendDbInstance является экземпляром Zend_Db или вы можете использовать одну из функций здесь, чтобы не полагаться на Zend php pdo: получить имя столбца таблицы

Затем для всех динамических таблиц вы можете получить псевдонимы и использовать $ tableName. * Для тех, которые вам не нужны псевдонимы:

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

Вы можете обернуть весь этот процесс в одну общую функцию и просто иметь более чистый код или стать более ленивым, если хотите :)

2
haknick

Если вы не хотите создавать псевдонимы, вы можете просто добавить префикс к именам таблиц.

Таким образом, вы можете лучше автоматизировать генерацию ваших запросов. Кроме того, лучше не использовать select * (это, очевидно, медленнее, чем просто выбор полей, которые вы нужно Более того, только явно указывайте имена полей, которые вы хотите иметь.

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
1
SchizoDuckie