2014-10-16 2 views
1

Мне нужно иметь дело с Java для создания ненадежного API, и я использую его с MySQL для запроса БД.Выберите префиксные столбцы из нескольких таблиц в Java с MySQL

Я довольно новичок в Java, и это может быть очень простой вопрос, но используется для фреймворков PHP, где эта проблема не существует, и мне было интересно, как это сделать на Java.

Я запрашиваю 3 таблицы, соединяющие их своими внешними ключами, и выяснил, что если две из этих таблиц имеют одинаковое имя столбца, возвращается только один из них. Один из последней таблицы, объявленный в заявлении from. Кажется, они переопределяют.

Например, если таблицы type_application и type_leaves имеют как name столбец, только name колонна из type_leaves будет возвращено в этом запросе:

select * from leaves, type_applications, type_leaves 
    where leaves.type_leave = type_leaves.id and 
    leaves.type_application = type_applications.id; 

Теперь, я знаю, что это может быть легко решена путем указания все необходимые имена столбцов с префиксом имени таблицы (в случае, если они дублируются) и используя as создать псевдоним:

select leaves.id, type_leaves.name as leaves_name, type_applications.name as application_name 
    from leaves, type_applications, type_leaves 
    where leaves.type_leave = type_leaves.id and 
    leaves.type_application = type_applications.id; 

Но это не похоже на лучшее решение для меня. Я бы предпочел продолжать использовать *, чтобы получить все поля (чего я всегда хочу).

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

Любое решение для этого? Каков способ справиться с этим в Java?

+0

Какая версия Java вы используете? Вы еще на Java 8? –

+0

Nop. Использование java 7. – Alvaro

+1

Stick с указанием всех столбцов. Это быстрее и лучше. Кроме того, используйте явный синтаксис соединения. – Strawberry

ответ

4

Я новичок Java тоже, так что я вас слышу;). Но прежде чем я попытаюсь дать вам ответ, я хочу сказать слово, если вы не возражаете. Ваш вопрос связан с Java и базами данных/SQL. Вы предоставили некоторый SQL, который объясняет несколько вещей о ваших таблицах БД и о том, что вы можете получить из запроса. Но ваша главная проблема связана с Java, и вы не предоставили Java-код, чтобы мы могли лучше понять, что вы пытаетесь выполнить, и где именно вы столкнулись с проблемами. При этом я надеюсь, что следующее даст вам представление о том, что вы можете сделать:

Прежде всего, ResultSet из вашего запроса содержит как столбцы name. Они не перезаписываются. Вот пример:

String sql = "select * from leaves, type_applications, type_leaves " + 
       "where leaves.type_leave = type_leaves.id and " + 
       "leaves.type_application = type_applications.id"; 

ResultSet rs = stmt.executeQuery(sql); 
DBTablePrinter.printResultSet(rs); 

Это будет печатать что-то вроде этого:

Printing 1 rows from table(s) LEAVES, TYPE_APPLICATIONS, TYPE_LEAVES 
+----+------------------------+------------+------------------+----+--------+ 
| ID | SOMETHING_ABOUT_LEAVES | ID |  NAME  | ID |  NAME  | 
+----+------------------------+----+--------------------+----+--------------+ 
| 1 | green     | 1 | application type 1 | 1 | leave type 1 | 
+----+------------------------+----+--------------------+----+--------------+ 

Как можно видеть, как name колонны там. (Я использовал служебный класс DBTablePrinter, который я написал. Если вы заинтересованы, вы можете найти его here). Я также хотел бы предложить, как сказал Strawberry в комментариях, рассмотреть возможность использования явного синтаксиса соединения.

Я использую другой БД (H2), поэтому я не уверен, если это будет работать с MySQL, но вы можете попробовать (он работал для меня):

// After executing the query 
rs.next(); 
System.out.println(rs.getString("TYPE_LEAVES.NAME")); 
System.out.println(rs.getString("TYPE_APPLICATIONS.NAME")); 

// Prints: 
// leave type 1 
// application type 1 

Если это не работает или вы действительно нужно префикс имен столбцов и доступ к ним с этими новыми именами, все, что я могу придумать что-то вроде этого:

ResultSetMetaData rsmd = rs.getMetaData(); 
int columnCount = rsmd.getColumnCount(); 

// A HashMap with column names as key 
Map<String, List<String>> columns = new HashMap<>(columnCount); 

// Loop through columns, rename as you wish 
for (int i = 1; i <= columnCount; i++) { 
    if (rsmd.getColumnLabel(i).equals("NAME")) { 
     if (rsmd.getTableName(i).equals("TYPE_LEAVES")) { 
      columns.put("L_NAME", new ArrayList<>()); 
     } else { 
      columns.put("APP_NAME", new ArrayList<>()); 
     } 
    } else { 
     columns.put(rsmd.getColumnLabel(i), new ArrayList<>()); 
    } 
} 

// Iterate over ResultSet rows, add values to columns 
while (rs.next()) { 
    for (int i = 1; i <= columnCount; i++) { 
     String columnName = rsmd.getColumnLabel(i); 
     String tableName = rsmd.getTableName(i); 
     if (columnName.equals("NAME")) { 
      if (tableName.equals("TYPE_LEAVES")) { 
       columns.get("L_NAME").add(rs.getString(i)); 
      } else { 
       columns.get("APP_NAME").add(rs.getString(i)); 
      } 
     } else { 
      columns.get(columnName).add(rs.getString(i)) 
     } 
    } 
} 

// Print, for example, first row values for L_NAME and APP_NAME columns 
System.out.println(columns.get("L_NAME").get(0)); 
System.out.println(columns.get("APP_NAME").get(0)); 

// Prints: 
// leave type 1 
// application type 1 
0

«select *» - это действительно плохая практика в большинстве серьезных случаев из-за производительности, я думаю, что это то же самое даже в PHP.

И, кроме того, столбец возвращается правильно, даже если вы используете «select *», вы можете использовать result.getMetaData(), чтобы проверить его.

for (int i=1; i<rs.getMetaData().getColumnCount(); i++) { 
    System.out.println(rs.getMetaData().getColumnName(i)); 
} 

В Java мире, ResultSet имеет getXXXXX (String ColumnName) методы, поэтому все имена столбцов должны быть уникальными в result.But вы также можете использовать getXXXX (INT columnIdx), чтобы извлечь все столбцы

+0

. Ваше решение печатает дважды в том же столбце «имя, имя», но оно не префиксает их чем-либо потом их отличить. – Alvaro

0

В этом случае один из столбцов может быть переименован.

Чтобы обойти эту проблему, вы можете запросить список столбцов из набора результатов, возвращаемого методом executeQuery (ResultSet.getMetaData). Это будет возвращать экземпляр http://docs.oracle.com/javase/7/docs/api/java/sql/ResultSetMetaData.html

  1. getColumnCount() возвращает количество столбцов в результате
  2. getColumnLabel (интермедиат колонок) возвращает имя этого столбца

Если два столбца имеет одинаковое имя " name ", метки могут отличаться для этих двух столбцов.

+0

Этот же ответ был предоставлен @sanigo, но он не решает префикс вывода имени столбца в любом случае. – Alvaro

+0

Разница в thisanswers - «ColumnLabel» вместо ColumnName. Оба эти столбца будут иметь одинаковое имя, но разные метки. –

+0

Все еще не префикс каждого столбца таблицы. – Alvaro

2

вы могли бы написать функцию, которая будет возвращать индекс столбца, основанный как на имя таблицы и имя столбца

public int getIndex(ResultSet rs, String table, String column) throws SQLException 
{ 
    for (int i=1; i < rs.getMetaData().getColumnCount(); i++) 
    { 
     if (rs.getMetaData().getTableName(i).equals(table) && rs.getMetaData().getColumnName(i).equals(column)) 
     { 
      return i; 
     } 
    } 
    return -1; 
} 

И использовать его так:

// TODO check if getIndex returns -1 
// You can use the appropriate getter off course 
System.out.println(rs.getObject(getIndex(rs, "type_application", "name"))); 
System.out.println(rs.getObject(getIndex(rs, "type_leaves", "name"))); 
+0

Было бы довольно утомительно, если бы число столбцов было большим. Скажем, 15, 25. – Alvaro

+0

Почему? О петле в getIndex? – ToYonos

+0

Я хочу использовать префикс для всех столбцов в каждой таблице. – Alvaro

1

Попробуйте получить недостающую колонку явно, как показано ниже:

select *,type_applications.name as type_applications_name 
    from leaves, type_applications, type_leaves 
    where leaves.type_leave = type_leaves.id and 
    leaves.type_application = type_applications.id; 
  1. В любом случае использование кросс-соединений не рекомендуется.
  2. Использование select * не рекомендуется.

Но если вы хотите выбрать * в любом случае, попробуйте использовать таблицу, чтобы обернуть результаты:

select * from (
select leaves.*, type_applications.*, type_leaves.* ,type_applications.name as type_applications_name 
    from leaves, type_applications, type_leaves 
    where leaves.type_leave = type_leaves.id and 
    leaves.type_application = type_applications.id; 
) 

PS: Я не проверял код, так что может быть опечаток, поэтому постарайтесь получить эту идею.

+0

Таблица для обертывания результатов не имеет никакого значения. – Alvaro

+0

упаковка не влияет на результаты. его использовали только потому, что вы хотели выбрать * на верхнем уровне. –

 Смежные вопросы

  • Нет связанных вопросов^_^