Как заставить Ruby MySQL возвращать PHP, подобный результату выбора DB

#mysql #ruby #prepared-statement

#mysql #ruby #подготовленное заявление

Вопрос:

Поэтому я использую PDO для подключения к БД следующим образом:

 $this->dsn[$key] = array('mysql:host=' . $creds['SRVR'] . ';dbname=' . $db, $creds['USER'], $creds['PWD']);
$this->db[$key] = new PDO($this->dsn[$key]);
  

Используя PDO, я могу затем выполнить MySQL SELECT, используя что-то вроде этого:

 $sql = "SELECT * FROM table WHERE id = ?";
$st = $db->prepare($sql);
$st->execute($id);
$result = $st->fetchAll();
  

Затем переменная $result вернет массив массивов, где каждой строке присваивается инкрементный ключ — первая строка, имеющая ключ массива 0. И тогда эти данные будут иметь массив данных DB, подобный этому:

 $result (array(2)
  [0]=>[0=>1, "id"=>1, 1=>"stuff", "field1"=>"stuff", 2=>"more stuff", "field2"=>"more stuff" ...],
  [1]=>[0=>2, "id"=>2, 1=>"yet more stuff", "field1"=>"yet more stuff", 2=>"even more stuff", "field2"=>"even more stuff"]);
  

В этом примере именами полей таблицы DB будут id, field1 и field2. И результат позволяет вам прокручивать массив строк данных, а затем получать доступ к данным, используя либо индекс (0, 1, 2), либо имя поля («id», «field1», «field2»). Большую часть времени я предпочитаю получать доступ к данным через имена полей, но доступ с помощью обоих способов полезен.

Итак, я сейчас изучаю ruby-mysql gem и могу извлекать данные из БД. Однако я не могу получить имена полей. Вероятно, я мог бы извлечь его из приведенного оператора SQL, но для этого требуется немного кодирования для отслеживания ошибок и работает только до тех пор, пока я не использую SELECT * FROM … в качестве оператора SELECT.

Итак, я использую таблицу, полную названий состояний и их сокращений, для моего тестирования. Когда я использую «SELECT State, Abbr ИЗ состояний» со следующим кодом

 st = @db.prepare(sql)
if empty(where)
  st.execute()
else
  st.execute(where)
end

rows = []
while row = st.fetch do
  rows << row
end
st.close

return rows
  

Я получаю такой результат:

 [["Alabama", "AL"], ["Alaska", "AK"], ...]
  

И я хочу получить такой результат:

 [[0=>"Alabama", "State"=>"Alabama", 1=>"AL", "Abbr"=>"AL"], ...]
  

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

В любом случае, чтобы сделать это? Я видел некоторые ссылки на выполнение подобных действий, но, похоже, для этого требуется модуль DBI. Я думаю, это не конец света, но это единственный способ? Или я могу сделать это только с ruby-mysql?

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

Спасибо, Гейб

Ответ №1:

Вы можете сделать это самостоятельно без особых усилий:

 expanded_rows = rows.map do |r|
    { 0 => r[0], 'State' => r[0], 1 => r[1], 'Abbr' => r[1] }
end
  

Или более общий подход, который вы могли бы обернуть в метод:

 columns = ['State', 'Abbr']
expanded_rows = rows.map do |r|
    0.upto(names.length - 1).each_with_object({}) do |i, h|
        h[names[i]] = h[i] = r[i]
    end
end
  

Таким образом, вы могли бы собрать то rows , что у вас есть сейчас, а затем перекачать этот массив массивов через что-то вроде того, что указано выше, и вы должны получить структуру данных, которую вы ищете, с другой стороны.

Существуют и другие методы row , которые вы получаете от st.fetch :

http://rubydoc.info/gems/mysql/2.8.1/Mysql/Result

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

Вы должны иметь возможность получать имена столбцов из row или st :

http://rubydoc.info/gems/mysql/2.8.1/Mysql/Stmt

но опять же, вам придется поэкспериментировать, чтобы разобраться с API. Извините, у меня нет ничего настроенного для работы с используемым вами MySQL API, поэтому я не могу быть более конкретным.

Комментарии:

1. На самом деле я ничего не имею против слоя. Моя главная проблема заключается в следующем — я начал с PHP несколько лет назад. И по привычке из других языков — написание кода, который, по словам других, не может быть написан для автоматизации инженерных задач, — я создал несколько полезных классов на PHP. Сейчас я просто пытаюсь воссоздать несколько наиболее полезных классов в Ruby, чтобы мое кодирование на Ruby могло быть очень похоже на мой код на PHP. Язык, который мне нравится, и, честно говоря, имеет лучшую документацию и отчеты об ошибках (ИМХО).

2. Извините, что вышесказанное предназначалось для ответа от pguaridario.

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

4. @gabe: Ваш Ruby должен выглядеть как Ruby, а не PHP; Я регулярно использую Ruby, Perl, JavaScript, C и три варианта SQL, поэтому я слышу вас о проблеме с несколькими языками, но когда в Риме… И, да, документация на php.net это намного лучше, чем что-либо в мире Ruby или Rails, и это факт (а не мнение 🙂

5. @gabe: Вам придется поиграть с методами в Result и Stmt, там должно быть что-то, что сообщит вам имена столбцов. Вы можете использовать документацию (ха-ха) в качестве списка методов, чтобы попробовать, а puts x.inspect для некоторых x посмотреть, что они вам дают.

Ответ №2:

Я понимаю, что все php-программисты — ковбои, которые считают, что использование уровня db — это обман, но вам действительно следует рассмотреть activerecord.

Комментарии:

1. К вашему сведению: использование уровня БД, который может обрабатывать несколько форматов БД со всевозможными дополнительными материалами, сопряжено с дополнительными накладными расходами. Если вы собираетесь запускать только 1 экземпляр своего кода, то да, о накладных расходах не стоит беспокоиться. Однако, если вы собираетесь запускать десятки экземпляров, тогда накладные расходы могут быть проблемой. Возможно, проблема решается многопоточностью, но не всегда решается этим. Иногда есть причины для минимизации накладных расходов и, таким образом, минимизации количества ненужных классов, которые вы включаете с помощью операторов require.

2. Ах, но пожертвовать немного накладными расходами для удобства — это путь ruby.

3. Да, я только что работал над параллельными / распределенными приложениями, где любой данный сервер может запускать десятки (скажем, около 100) экземпляров одновременно. Я узнал, как удобство на этом уровне, когда одновременные экземпляры могут вывести ваш сервер из строя. Где чистый, оптимизированный код, который активно управляет памятью, может легко обрабатывать нагрузку, а затем и некоторые другие. Итак, для моих целей … удобство в коде означает необходимость покупать и обслуживать гораздо больше машин.

4. В таком случае зачем вам переключаться с php на ruby?

5. @gabe — php имеет phpunit с интеграцией сервера selenium. Когда я пишу php, я пишу свои модульные тесты с помощью phpunit, а затем пишу свои функциональные тесты, подклассы класса seleniumtestcase, который поставляется с phpunit. Если вы хотите по-настоящему пофантазировать, вы можете использовать jenkins и автоматизировать весь процесс.