Mysql циклы в запросе: Циклы в MySQL / Под рукой / Garb.ru

php — Вложенные циклы с запросами в mysql (базу)


Вопрос задан


Изменён
7 лет 8 месяцев назад


Просмотрен
530 раз

Есть вот такой вот код:

$unique_country = "SELECT DISTINCT country FROM data_base"; // узнаем уникальные страны

Далее узнаем игры в этой стране и к каждой игре узнаем состав команд:

while($uc_result = mysqli_fetch_assoc($unique_country)) {
    $game = "SELECT * FROM game WHERE country='".$uc_result['country']."'"; //скажем, ближайшие игры этой страны
    while($g_result = mysqli_fetch_assoc($game)) {
        $players_for_game_team_1 = "SELECT * FROM players WHERE game='".$g_result['id']."' AND TEAM='1'"; //состав на игру команды 1
        $players_for_game_team_2 = "SELECT * FROM players WHERE game='". $g_result['id']."' AND TEAM='2'";  //состав на игру команды 2
        while($team1_players = mysqli_fetch_assoc(...
        while($team2_...
    }
}

То-есть получается, что к цикле есть цикл в котором происходит каждый раз запрос в базу, а то и по 2-3 запроса в базу и по несколько циклов, правильное ли это решение? Есть более лучшее решение (к примеру будет ли этом правильно сделать через вложенные запросы и как их разобрать с помощью php)? Если да, напишите, пожалуйста, хотя бы коротко о главном, а то нигде не могу найти подобной информации… буду очень благодарен, а то не знаю правильно ли так делать и остановился, что бы двигаться дальше…

Если сделать вложенные запрос то получится примерно такой результат:

страна1 | игра1 | команда1 игрок 1 для игры1 | команда2 игрок 1 для игры1
страна1 | игра1 | команда1 игрок 2 для игры1 | команда2 игрок 2 для игры1
страна1 | игра1 | команда1 игрок 3 для игры1 | команда2 игрок 3 для игры1
страна1 | игра2 | команда1 игрок 1 для игры1 | команда2 игрок 1 для игры1

как такой вложенный запрос забирать с помощью php?

  • php
  • mysqli

Данный код повысит нагрузку как на базу, так и на сам интерпретатор.

В Вашем случае нужно анализировать сам запрос и оптимизировать его.

Ссылки к прочтению:

  1. MySQL JOIN
  2. Вложенные SELECT

UPD:
Возможно автору нужна документация с примерами: Пример работы с запросом в виде ассоциативного массива

По ссылке приведен пример, как забирать результат в виде ассоциативного массива. Ассоциативный массив — массив с ключами в виде названия столбцов (конкретно эта ситуация), вместо цифровых значений.

UPD2:

Прошу прощения, не заметил у автора в коде отсутствие исполнения запроса: $result = $mysqli->query($game). Эта строка будет «говорить» php исполнить запрос, содержащийся в переменной $game.

Для более полного понимания ситуации, ознакомьтесь внимательно с приведенными примерами в документации по ссылкам!






10







Зарегистрируйтесь или войдите

Регистрация через Google

Регистрация через Facebook

Регистрация через почту

Отправить без регистрации

Почта

Необходима, но никому не показывается

Отправить без регистрации


Почта

Необходима, но никому не показывается





Нажимая на кнопку «Отправить ответ», вы соглашаетесь с нашими пользовательским соглашением, политикой конфиденциальности и политикой о куки


Выгружаем из базы данных с помощью Python — Разработка на vc.

ru

Задача на выгрузку данных из одной таблицы, с одним условием для фильтра решается посредством создания простого SQL-запроса. Но она легко становится трудоемкой в исполнении, если в фильтрации применить множество условий. Давайте представим, что необходимо выгрузить данные из одной таблицы по фильтру, где первые две цифры ИНН начинаются на «66». SQL-запрос будет выглядеть так:

10 894
просмотров

select * from tabl where inn like ‘66%’

Вроде ничего сложного, но, если изменить условие фильтрации на поиск по 2 млн уникальных ИНН, SQL-запрос будет выглядеть так:

select * from tabl where inn = ’66******01′
or inn = ’66******02′
or inn = ’66******03′
or inn = ’66******04′
or inn = ’66******05′
or inn = ’66******06′
or inn = ’66******07′

or inn = ’66******nn’

Исходя из своего опыта, такой запрос запустить не получится из-за ограничения СУБД на количество условий в 10 тыс. значений (Ограничения СУБД могут быть разные). В нашем случае потребуется создать 200 запросов и запустить их по отдельности. В итоге мы получим 200 файлов с данными, которые необходимо собрать в один. Сложно представить сколько потребуется на это времени и сил, но с помощью Python и библиотеки «cx_Oracle» задача решается легко.

Используем библиотеки:

import cx_Oracle
import pandas as pd
import time

Проверяем версию (должна быть > 3.0):

cx_Oracle.__version__

Прописываем дескриптор соединения Oracle:

ConnectStr = «»»(DESCRIPTION=(ADDRESS=(PROTOCOL=…)(Host=…)
(Port= … ))(CONNECT_DATA=(SERVICE_NAME= … )))»»»

Прописываем логин и пароль (при доменной аутентификации оставляем ‘/’):

Login = ‘IVANOV/PASSWORD’

Функция, в которой создается экземпляр класса connect, он обеспечит взаимодействие с сервером Oracle:

def getConn(Login, ConnectStr):
conn=None
nn=0
while conn==None:
try:
conn=cx_Oracle. connect(Login + ‘@’ + ConnectStr)
except cx_Oracle.DatabaseError as e:
ers,=e.args
nn=nn+1
print (nn,end=’\r’)
if ers.code!=2391:
print (‘Ошибка Oracle ‘, ers.code)
break
time.sleep(5)
return conn

Функция, в которой создается курсор и выполняется запрос:

def dfFromOracle(connection, sql):
us=0
outDF=pd.DataFrame()
success = ‘False’
with connection.cursor() as cursor1:
cursor1.execute(sql)
trn=10
while success == ‘False’ and trn>0:
try:
outheader=[desc[0] for desc in cursor1.description]
#При вызове «cursor1.fetchall()» возвращается список записей, каждая из которых
#является кортежем (неизменяемым списком) полей разного типа
outDF=pd. DataFrame(cursor1.fetchall())
success = ‘True’
print(‘Результат получен из базы’)
us = 1
except:
trn=trn-1
print(‘Error’)
time.sleep(60)
return outheader, outDF, us

Подключаемся к серверу:

getConn(Login, ConnectStr)

Файл, в котором одна колонка со всеми значениями ИНН:

f = open(‘inn_in_.txt’,’r’,encoding=’UTF-8′)

Присваиваем имя файла, в который выгрузится результат:

new_file = ‘new_file.csv’

r=» — для собора строк в «with», которые подставим в SQL-запрос,
h = 0 — проверки наличия заголовков,
l = 0 — счетчик строк для запуска SQL-запроса,
ll = 0 — счетчик строк для проверки на остаток,
cnt = 10000 — количество строк для запуска SQL-запроса.

Цикл для создания и запуска SQL-запросов:

for row in f:
l += 1
if r == »: #Формируем «where» — список ИНН для фильтрации
r = r + ‘inn = \» + row. replace(‘\n’,») + ‘\»
else:
r = r + ‘or inn = \» + row.replace(‘\n’,») + ‘\»
if l % cnt == 0: #Проверка на 10 000 строк
ll += l
sql = ( ‘select * from tabl where’ + r ) #Сформированный SQL-запрос

Отправляем SQL-запрос и обрабатываем полученную выгрузку:

with getConn(Login,ConnectStr) as con1:
if h==0:
_header,result,us = dfFromOracle(con1, sql)
header = ‘;’.join(_header)+’\n’
myfile=open(new_file, ‘w’,encoding=’UTF-8′)
myfile.writelines(header)
myfile.close()
h=1
result.to_csv(new_file, sep=’;’,encoding=’UTF-8′,mode=’a’,header=None,index=False)
r=»
print(‘Выгружено: ‘+str(l) )
if l != ll: #Если последний список менее 10 000 строк
sql = ( ‘select * from tabl where’ + r ) #Сформированный SQL-запрос
with getConn(Login,ConnectStr) as con1:
_header,result,us = dfFromOracle(con1, sql)
if h==0:
header = ‘;’. join(_header)+’\n’
myfile=open(new_file, ‘w’,encoding=’UTF-8′)
myfile.writelines(header)
myfile.close()
h=1
result.to_csv(new_file, sep=’;’,encoding=’UTF-8′,mode=’a’,header=None,index=False)
print(‘Выгружено: ‘+str(l) )
print(‘Выгрузка завершена’)
f.close()

Таким образом, с помощью Python мы автоматизировали процесс создания, запуска SQL-запросов и сохранения результатов в один файл, избежали больших трудозатрат, при этом:

  • исключили ошибки, возможные при перечислении списка условий для фильтрации, что снизило вероятность потери данных;
  • настроили процесс создания, запуска SQL-запросов и сохранения результатов в один файл порционно, что дает возможность в случае обрыва сессии не повторять заново запросы с уже отработавшими условиями, а продолжить с условий, на которых обрыв произошел.

рискованных вложенных запросов MySQL в цикле PHP | by rahul g

Рискованные вложенные запросы внутри цикла в PHP

В предыдущей статье я получил хороший отзыв о ошибках, допущенных людьми в PHP .

Здесь я забыл упомянуть самую распространенную ошибку многих разработчиков. Они пишут вложенные запросы внутри цикла PHP while.

  • Выполнение родительского запроса
  • Извлечение результата с помощью цикла while
  • И с использованием другой запрос внутри цикла по идентификатору результата родительского запроса.

Поверьте мне, MySQL много плачет во время этой практики.

Итак, давайте посмотрим, что на самом деле происходит за кулисами.

MySQL Crying in the Darkness

Здесь у нас есть 2 таблицы:

  • вопросов
  • ответов

Обе имеют некоторые данные, и question_id является внешним ключом в таблице ответов.

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

родительский запрос -> результат -> для каждого -> дочерний запрос -> добавить с родительским-> закончить

Это вызывает много запросов к базе данных и заставляет MySQL плакать в углу тьмы.

Результат вызова функции

#2 Улучшенная практика запроса результатов

У нас есть та же таблица, что упоминалась выше. Но подход другой. Посмотрим.

В приведенном выше примере я вызвал 2 отдельных запроса для родительского и дочернего элементов.

  • Сначала я получил результаты от родителя, а затем получил только идентификаторы родительского результата, используя функцию array_column(). (т.е. 1,2,3)
  • Затем использовал в ключевом слове MySQL , чтобы получить результат за один раз.
  • Затем выполните итерацию по массиву вопросов и для каждого вопроса отфильтруйте ответы на основе question_id и объедините результат.

Теперь вопрос в том, насколько этот подход полезен, мы все еще перебираем массив вопросов и объединяем дочерний результат. Итак, ответ прост, на этот раз мы не вызываем базу данных снова и снова и снова, мы обрабатываем операции на уровне PHP.

Основная идея функции array_filter() состоит в том, чтобы просто отфильтровать требуемый результат, который представляет собой не что иное, как поиск и возврат массива результатов за сценой. Этот подход использует ресурсы на стороне PHP, и это нормально.

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

#3 Анализ

В первом подходе, если есть 500 вопросов, то будет выполнено 500 вложенных запросов. Это можно минимизировать и с помощью нумерации страниц , но все же это плохая практика.

Во втором подходе мы используем ресурсы сервера, а сам PHP обрабатывает эти вещи. Что вызывает много использования памяти.

В обоих случаях мы можем использовать разбиение на страницы. Вот почему сам Google не показывает все результаты на одной странице.

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

Итак, это был мой подход к обработке вложенных запросов в PHP для повышения производительности. Просто хотел показать вам разные точки зрения на проблему.

Надеюсь, вам понравилось и вы узнали что-то новое.

Давайте подключимся и в другом месте:

https://www.linkedin.com/in/rahul-gohil-602614187

Массив циклических запросов и отправка в mysql — General

ketpa

#1

У меня есть массив запросов

Я пытаюсь отправить msg.topic в mysql следующим образом

, но он отправляет мне только один запрос

Как зациклить запрос как msg.topic и отправить в mysql?

бакман2

#2

в функции может быть только 1 оператор возврата.

Я предполагаю, что query.length исходит из msg.query.length .
Но для отправки сообщений в цикле используйте node.send({ msg.topic: query[i] })
и добавьте return null внизу

Чтобы сделать его короче:

 msg.query .forEach(запрос => node.send({тема: запрос}))
вернуть ноль
 

1 Нравится

E1cid

#3

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

1 Нравится

бакман2

#4

Да, извините, это лучшая формулировка; возврат = выход

Немного странно, потому что я все время использую это в «защитных оговорках»

1 Нравится

кетпа

#5

Да, извините, это лучшая формулировка; return = exit
Я пытаюсь «вернуть выход» «выход» «возврат = выход» и его ошибка.