|
|
|
Объединение таблиц HELP!
|
|||
|---|---|---|---|
|
#18+
Здравствуйте! Если не трудно, подскажите новичку в MySQL как правильно организовать решение такой задачи: Сначала, как это уже реализовано: Есть таблица с данными. Изначально данные берутся их таблиц Excel, VBA-скриптом я их конвертирую в формат CSV (при обычном сохранении в CSV не сохраняются некоторые особенности XLS-файла). PHP-скриптом на сервере загоняю в БД MySQL. В дальнейшем, строки таблицы пополняются новыми полями через WEB-интерфейс с участием того же PHP. Источник периодически обновляется, соответсвенно периодически база пополняется новыми данными из Экселя. Проблема: При обновлении приходится проверять, есть ли запись с таким названием в таблице БД и если есть, обновлять поля. Если нет - создавать. В итоге куча обращений к бд, медленная работа и оконкание тайм-лимита на выполнение PHP-скрипта. Плюс остаются "мёртвые" строки, которых уже нет в Экселе. Что хочу: 1) Перед обновлением базы выкинуть из неё все строки, у которых пусто в "дополнительных" полях и переименовать таблицу. (чтоб потом мёртвых строк не было) 2) Заносить данные в пустую таблицу безо всяких лишних проверок. 3) "Слить" две таблицы между собой так, чтобы в строки, которые есть и там и там попали дополнительные поля (введённые через WEB-интерфейс), которых не было в экселе, а строки, которых нет в экселевских данных игнорировались. И сделать это надо средствами MySQL, чтобы работало как можно быстрее и уложиться в тайм-лимит PHP (база приличная по объёму и если пытаться прочитать исходную базу в массив PHP, новую в другой и там с ними работать, то будет недостаточно быстро, да и памяти много уйдёт). Буду очень признателен, если подскажете, какими SQL-командами можно это сделать. Если написал какие-то заблуждения - поправьте. Может есть другой алгоритм решения задачи... ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 31.10.2005, 16:09:32 |
|
||
|
Объединение таблиц HELP!
|
|||
|---|---|---|---|
|
#18+
Логика работы - не зачот. Так сделать можно, но это иррациональный путь. Используй конструкцию load data infile для закачки cvs в пустую табличку, потом инсертить новые данные в стационарную таблицу и обновлять измененые в ёкселе строки опять же запросом, который и описыват твои условия. Вот собственно и все. Главное, чтобы был доступ к файлу cvs от сервера, тогда все будет сделано достаточно быстро. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 31.10.2005, 16:13:53 |
|
||
|
Объединение таблиц HELP!
|
|||
|---|---|---|---|
|
#18+
Валентин КЛогика работы - не зачот. Так сделать можно, но это иррациональный путь. Используй конструкцию load data infile для закачки cvs в пустую табличку, потом инсертить новые данные в стационарную таблицу и обновлять измененые в ёкселе строки опять же запросом, который и описыват твои условия. Вот собственно и все. Главное, чтобы был доступ к файлу cvs от сервера, тогда все будет сделано достаточно быстро. Перечитал - не очень понятно выглядит. Главный вопрос вот в чём: Например есть таблица с колонками: "Name" "Age" "Phone" "Interests" И есть входные данные (новая таблица из Excel), которые должны полностью переписать эту таблицу, удаляя тех людей, "Name" которых в этих данных отсутствует. Но колонки "Interests" нет в этих новых данных и его необходимо сохранить из старой таблицы. В общем как объединить эти две таблицы, чтоб из записей в старой таблице поле "Interests" попало в новую таблицу в запись с тем же "Name". Ну и чтоб записи с именем, отсутствующим в новой таблице, никуда не копировались. Если я буду инсертить новые данные в старую таблицу - останутся мёртвые записи - или я ошибаюсь? Я прошу написать как это сделать командами MySQL. Раньше не приходилось работать с БД и тот код, в котором приходится разбираться, написан другими людьми... В общем чувствую себя даже не чайником а самоваром :(. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 31.10.2005, 16:36:46 |
|
||
|
Объединение таблиц HELP!
|
|||
|---|---|---|---|
|
#18+
Stepanow Главный вопрос вот в чём: Например есть таблица с колонками: "Name" "Age" "Phone" "Interests" И есть входные данные (новая таблица из Excel), которые должны полностью переписать эту таблицу, удаляя тех людей, "Name" которых в этих данных отсутствует. Но колонки "Interests" нет в этих новых данных и его необходимо сохранить из старой таблицы. В общем как объединить эти две таблицы, чтоб из записей в старой таблице поле "Interests" попало в новую таблицу в запись с тем же "Name". Ну и чтоб записи с именем, отсутствующим в новой таблице, никуда не копировались. У записей есть ключевые поля? Stepanow Если я буду инсертить новые данные в старую таблицу - останутся мёртвые записи - или я ошибаюсь? Я прошу написать как это сделать командами MySQL. Раньше не приходилось работать с БД и тот код, в котором приходится разбираться, написан другими людьми... В общем чувствую себя даже не чайником а самоваром :(. Нет не останутся, обработать нужно будет несколькими запросми, которые соберут из 2-х таблиц одну, в которой будут учтены условия. Кстати MySQL тут не при чем, читай про SQL тут http://www.mysql.ru/docs/gruber/ А мануал по MySQL тут http://dev.mysql.com/doc/refman/5.0/en/index.html ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 31.10.2005, 16:42:01 |
|
||
|
Объединение таблиц HELP!
|
|||
|---|---|---|---|
|
#18+
Ок, спасибо за ссылочку, сейчас почитаю. В моей книге по PHP про MySQL маловато информации. А насчёт ключевых полей... Я не силён в терминологии, но если имеется в виду PRIMARY KEY, то в реальной программе есть ещё столбец ID с флагами AUTO_INCREMENT и PRIMARY KEY для технических нужд, поэтому в пример я его не включил. Ну а идентификация записи происходит по полю "Name". ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 31.10.2005, 18:23:19 |
|
||
|
Объединение таблиц HELP!
|
|||
|---|---|---|---|
|
#18+
Валентин К Используй конструкцию load data infile для закачки cvs в пустую табличку, потом инсертить новые данные в стационарную таблицу и обновлять измененые в ёкселе строки опять же запросом, который и описыват твои условия. Вот собственно и все. Главное, чтобы был доступ к файлу cvs от сервера, тогда все будет сделано достаточно быстро. Как я понимаю, файл должен находиться в каталоге базы данных на сервере, а это невозможно в моём случае (обычный хостинг, где одна СУБД MySQL обслуживает много хостов). Если же файл находится на локальном компьютере, субд даже не знает о его (лок. компьютера существовании), ведь клиентом для неё является PHP, работающий на том же сервере, а не на моём компе. Как же указать размещение файла? ЗЫ: я могу закачать файл на сервер и указать путь к нему относительно корневой для веб-сервера папки (или относительно её фактического расположения /domains/mydomain/public_html/ ) ? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 07.11.2005, 15:11:40 |
|
||
|
Объединение таблиц HELP!
|
|||
|---|---|---|---|
|
#18+
Не факт, что правильно понял проблему, но... У вас наверняка есть какой-то столбец или их совокупность, которая однозначно определяет какую-то конкретную запись. Вероятно, в данном случае имя, или синтетический id, но факт тот, что по нему либо уже построен первичный ключ, либо есть возможность построить индекс типа UNIQUE. Про него вам лучше почитать в документации, но суть в том, что он накладывает ограничение уникальности на выбранные для него столбцы. Тем же свойством обладает и первичный ключ. Если теперь использовать INSERT для занесения данных в таблицу, и указывать значение этих уникальных полей, в случае, если в базе уже есть запись с этим уникальным значением -- СУБД вернёт ошибку и, главное в этом случае, эта запись добавлена не будет. Чтобы СУБД не ругалась тут почём зря, используем INSERT IGNORE, что в данном случае вполне оправданно и адекватно. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 07.11.2005, 15:42:16 |
|
||
|
Объединение таблиц HELP!
|
|||
|---|---|---|---|
|
#18+
DocAlНе факт, что правильно понял проблему, но... У вас наверняка есть какой-то столбец или их совокупность, которая однозначно определяет какую-то конкретную запись. Вероятно, в данном случае имя, или синтетический id, но факт тот, что по нему либо уже построен первичный ключ, либо есть возможность построить индекс типа UNIQUE. Про него вам лучше почитать в документации, но суть в том, что он накладывает ограничение уникальности на выбранные для него столбцы. Тем же свойством обладает и первичный ключ. Если теперь использовать INSERT для занесения данных в таблицу, и указывать значение этих уникальных полей, в случае, если в базе уже есть запись с этим уникальным значением -- СУБД вернёт ошибку и, главное в этом случае, эта запись добавлена не будет. Чтобы СУБД не ругалась тут почём зря, используем INSERT IGNORE, что в данном случае вполне оправданно и адекватно. INSERT IGNORE, как я понял, предназначена для добавления строк, ключи которых уже есть в базе. Хорошая идея, возможно даже сохранятся нужные мне столбцы, которые есть в базе и нет в Экселе. Но мне надо одновременно и удалить данные, которых уже нет в экселе, а они тоже ведь никуда не денутся... В общем, почитав про SQL, я понимаю решение этой задачи так: текущая таблица называется Cur_tb и содержит поля: name NOT NULL PRIMARY KEY, age, phone, interests. Для простоты все char(50). -- 1. Создаю новую таблицу для новых данных. CREATE TABLE New_tb LIKE Cur_tb; -- 2. Загружаю данные из экселя в новую таблицу -- (пока не разберусь с load data infile буду инсертить по-старому :-) INSERT INTO New_tb VALUES ('Аня Пупкина', '1-9-1991', '555-55-55', NULL); .... INSERT INTO New_tb VALUES ('Юра Ухов', '18-1-1980', '777-77-77', NULL); -- 3. Копируем поле interests из старой таблицы в новую UPDATE New_tb, Cur_tb SET New_tb.interests = Cur_tb.interests WHERE New_tb.name = Cur_tb.name; -- 4. Подменяем старую таблицу новой RENAME TABLE Cur_tb TO Old_tb, New_tb TO Cur_tb; -- 5. Удаляем старую таблицу DROP TABLE Old_tb; Сейчас попробую через PhpMyAdmin проверить работоспособность "творения"... ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 07.11.2005, 17:52:20 |
|
||
|
Объединение таблиц HELP!
|
|||
|---|---|---|---|
|
#18+
Ура, работает! :) Немного усложним задачу. Вместо плоской базы, разобьём её на подкаталоги. Добавляется таблица Dir_tb с полями "id" NOT NULL AUTO_INCREMENT PRIMARY KEY, ,"cat_name". Первый int, второй по традиции char(50); А таблица с данными Cur_tb обзаводится ещё одним столбцом "cat" NOT NULL REFERENCES Dir_tb(id) - внешним ключом. теперь надо при чтении из excel создавать ещё и New_Dir_tb, причём поля id в ней будут созданы динамически и скорее всего не совпадут с полями id Dir_tb, поэтому надо ориентироваться на поле name. Соответственно оператор Update усложняется и в нём надо проверять не только поле name, но и поле name таблицы Dir_tb, связанное с данной записью по внешнему ключу... Буду думать, как это реализовать, если кто знает - подскажите. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 07.11.2005, 18:52:37 |
|
||
|
Объединение таблиц HELP!
|
|||
|---|---|---|---|
|
#18+
Сделал. Дальше ещё усложняется задача, а пока вот как решена текущая: Код: plaintext 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53. 54. 55. 56. 57. 58. 59. 60. 61. 62. 63. 64. 65. 66. 67. 68. 69. 70. 71. 72. 73. 74. 75. А теперь слабо написать оператор UPDATE взамен моего, который справился бы со следующей задачей ?: Вместо каталогов первого уровня, как в предыдущем примере, появляется дерево каталогов. Вложенность достигается добавлением ещё одной колонки в таблице Dir_tb. Эта колонка называется cat (или как-то ещё, если для алгоритма будет вредно совпадение с одноимённым полем основной таблицы Cur_tb) и содержит id родительского каталога по отношению к текущему, или NULL, если это корневой каталог. Возможно что она REFERENCES Dir_tb(id), но я не знаю, как сделать тогда в ней NULL, ведь поле id NOT NULL. В общем надо как-то пройтись по дереву каталогов до нуля, сравнивая при этом поля cat_name. Возможно ли это в принципе одним запросом к базе сделать? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 07.11.2005, 23:50:53 |
|
||
|
Объединение таблиц HELP!
|
|||
|---|---|---|---|
|
#18+
Или проще на этапе ввода таблицы каталога присваивать каталогам id из старой таблицы каталога (если такие записи там есть), сравнивая имена и родительские id, и иметь потом возможность сравнивать старую таблицу с новой, не вытаскивая поля с именами и именами каталога а опирась только на id? На этапе ввода данных это очевидно медленнее, а на этапе UPDATE - должно быть быстее... Какой алгоритм предпочесть? ЗЫ: В экселе, понятное дело, никаких ID нет, их приходится формировать при вводе строки в базу. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 08.11.2005, 00:20:40 |
|
||
|
Объединение таблиц HELP!
|
|||
|---|---|---|---|
|
#18+
StepanowИли проще на этапе ввода таблицы каталога присваивать каталогам id из старой таблицы каталога (если такие записи там есть), сравнивая имена и родительские id, и иметь потом возможность сравнивать старую таблицу с новой, не вытаскивая поля с именами и именами каталога а опирась только на id? На этапе ввода данных это очевидно медленнее, а на этапе UPDATE - должно быть быстее... Какой алгоритм предпочесть? ЗЫ: В экселе, понятное дело, никаких ID нет, их приходится формировать при вводе строки в базу. Насколько я понял из сырцов команд ключом для людей является поле name, вот по нему и сравнивай в update, по нему можно легко отобрать и регионы, если нужно. update пиши аккуратно и пробуй только на тестовой копии. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 08.11.2005, 13:52:58 |
|
||
|
Объединение таблиц HELP!
|
|||
|---|---|---|---|
|
#18+
А вот такой вопрос: Можно ли при инсерте в одну базу одновременно выполнять выборку из другой отдельных столбцов и инсертить их вместе с остальными данными? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 10.11.2005, 02:04:26 |
|
||
|
|

start [/forum/topic.php?fid=47&msg=33364271&tid=1853458]: |
0ms |
get settings: |
5ms |
get forum list: |
9ms |
check forum access: |
2ms |
check topic access: |
2ms |
track hit: |
20ms |
get topic data: |
5ms |
get forum data: |
1ms |
get page messages: |
27ms |
get tp. blocked users: |
1ms |
| others: | 194ms |
| total: | 266ms |

| 0 / 0 |
