Warning: Cannot use a scalar value as an array in /home/admin/public_html/forum/include/fm.class.php on line 757

Warning: Invalid argument supplied for foreach() in /home/admin/public_html/forum/include/fm.class.php on line 770

Warning: Invalid argument supplied for foreach() in /home/admin/public_html/forum/topic.php on line 737
Форумы портала PHP.SU :: случайная запись в MySQl

 PHP.SU

Программирование на PHP, MySQL и другие веб-технологии
PHP.SU Портал     На главную страницу форума Главная     Помощь Помощь     Поиск Поиск     Поиск Яндекс Поиск Яндекс     Вакансии  Пользователи Пользователи


 Страниц (2): [1] 2 »   

> Без описания
Butch
Отправлено: 11 Апреля, 2007 - 19:17:17
Post Id


Новичок


Покинул форум
Сообщений всего: 6
Дата рег-ции: Март 2007  


Помог: 0 раз(а)




как выбрать случайную запись в базе MySQL (PHP) или как на PHP можно выбрать случайное число в диапазоне >1 <количество записей в базе MySQL? искал в PHP функцию типа random - не нашел..
 
 Top
valenok Модератор
Отправлено: 11 Апреля, 2007 - 19:28:33
Post Id



Здесь могла бы быть ваша реклама


Покинул форум
Сообщений всего: 4574
Дата рег-ции: Июль 2006  
Откуда: Israel


Помог: 3 раз(а)




В MySQL нет таковой.
PHP:
скопировать код в буфер обмена
  1.  
  2. <?
  3.  // Возможно сначала узнать колво записей
  4. $num = mysql_num_rows(mysql_query("SELECT `id` FROM `table`"));
  5.  
  6. // Потом сгенерировать случайное число в диапазоне 1 - $num
  7. $rnd = rand(1,$num);
  8.  
  9. // А потом на основе него выбрать запись:
  10. $row = mysql_fetch_row(mysql_query("SELECT * FROM `table` WHERE `id`=".$rnd));
  11.  
  12.  


-----
Truly yours, Sasha.
 
My status
 Top
evgenijj
Отправлено: 12 Апреля, 2007 - 19:10:34
Post Id



Участник


Покинул форум
Сообщений всего: 1212
Дата рег-ции: Авг. 2006  
Откуда: Москва


Помог: 10 раз(а)




Цитата:
В MySQL нет таковой.

Я выбирал случайный товар из каталога вот так
PHP:
скопировать код в буфер обмена
  1.  
  2. <?PHP
  3. $query = "SELECT id_prd, code, title, info, price, image
  4.                 FROM ".TABLE_PRODUCTS."
  5.                 WHERE 1 ORDER BY RAND() LIMIT 1";
  6. ?>
  7.  
 
 Top
valenok Модератор
Отправлено: 12 Апреля, 2007 - 22:09:10
Post Id



Здесь могла бы быть ваша реклама


Покинул форум
Сообщений всего: 4574
Дата рег-ции: Июль 2006  
Откуда: Israel


Помог: 3 раз(а)




Значит есть.
Правда в документации пишут что функцию не стоит применять вместе с ORDER BY так как она повторяется многократно и влёчёт нагрузку на систему.


-----
Truly yours, Sasha.
 
My status
 Top
evgenijj
Отправлено: 13 Апреля, 2007 - 10:50:02
Post Id



Участник


Покинул форум
Сообщений всего: 1212
Дата рег-ции: Авг. 2006  
Откуда: Москва


Помог: 10 раз(а)




valenok пишет:

Правда в документации пишут что функцию не стоит применять вместе с ORDER BY так как она повторяется многократно и влёчёт нагрузкуна систему.

Хм... Тогда переделаю
 
 Top
valenok Модератор
Отправлено: 13 Апреля, 2007 - 14:33:13
Post Id



Здесь могла бы быть ваша реклама


Покинул форум
Сообщений всего: 4574
Дата рег-ции: Июль 2006  
Откуда: Israel


Помог: 3 раз(а)




Я реализовывал алгоритм случайного выбора с условиями следующим образом

Id | name | char | num
---------------------------
1 | ns22 | A | 1
2 | 3432 | B | 1
3 | abcd | B | 3
4 | ccpc | C | 3
5 | nq2d | A | 1
6 | qq32 | B | 2
7 | awcd | B | 2
8 | csdc | C | 3

Условие было: выбрать случайную запись где char = A и num = 1


Для реализации два пути.

Путь А
PHP:
скопировать код в буфер обмена
  1.  
  2. $r = mysql_query("SELECT `id` FROM `table` WHERE `char`='A' AND `num`=1 ");
  3. while($id = mysql_result($r,0)) $available_ids[] = $id;
  4.  
  5. $rand = rand( 0 , (count($available_ids)-1) );
  6. $id = $available_ids[$rand];
  7.  

Недостатки:
* Планируемые 15 000 строк таблиц приведут к тому что массив окажется слишком большим, скрипт будет исполняться очень долго и использовать много системных ресурсов.


Путь Б был разделить основную таблицу на несколько под таблиц:
Цитата:
A 1
Id | name | char | num
---------------------------
1 | ns22 | A | 1
2 | nq2d | A | 1

A 2
Id | name | char | num
---------------------------


A 3
Id | name | char | num
---------------------------

B 1
Id | name | char | num
---------------------------
1 | 3432 | B | 1

B 2
Id | name | char | num
---------------------------
1 | qq32 | B | 2
2 | awcd | B | 2

Недостатки:
* Выбрать случайный id придётся тем же способом - подсчётка кол-ва. записей, потом генерации случайного числа от 1 до кол-ва. записей и выбирания строки с этим id
* Разделение тут лишь по двум параметрам num и сhar у кадого из которых всего 3 возможных значения, потому таблиц будет всего 9. А если понадобится больше, таблиц не сосчитаешь.

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


А также третий способ упомянутый выше:
SELECT * FROM `table` WHERE `char`='A' AND `num`=1 ORDER BY RAND() LIMIT 1
Прилично будут тратиться системные ресурсы, хотя не известно на сколько по отношению к двум приведённым выше способам. Выглядит наиболее оптимальный вариант..


-----
Truly yours, Sasha.
 
My status
 Top
valenok Модератор
Отправлено: 13 Апреля, 2007 - 21:26:33
Post Id



Здесь могла бы быть ваша реклама


Покинул форум
Сообщений всего: 4574
Дата рег-ции: Июль 2006  
Откуда: Israel


Помог: 3 раз(а)




Пришла в голову следующая идея.
Если mysql выполняет функцию rand() многократно, пусть это делает пхп.

PHP:
скопировать код в буфер обмена
  1.  
  2. $rnd = rand() / 10000 ;
  3. SELECT * FROM `table` WHERE `char`='A' AND `num`=1 ORDER BY $rnd LIMIT 1
  4.  


-----
Truly yours, Sasha.
 
My status
 Top
evgenijj
Отправлено: 13 Апреля, 2007 - 22:13:27
Post Id



Участник


Покинул форум
Сообщений всего: 1212
Дата рег-ции: Авг. 2006  
Откуда: Москва


Помог: 10 раз(а)




Что-то я твою идею не понял. Пусть $rnd = rand(). Т.е. это - число.
Тогда запрос будет выглядеть так
SELECT * FROM `table` WHERE `char`='A' AND `num`=1 ORDER BY 1234 LIMIT 1
При запросе
SELECT * FROM `table` WHERE `char`='A' AND `num`=1 ORDER BY RAND() LIMIT 1
функция MySQL RAND() для каждой записи выбирает случайное число - по нему и идет сортировка. А как сортировать по константе? Другими словами ORDER BY 1234 не имеет смысла и MySQL будет все время возвращать одну и ту же запись (до тех пор, пока мы не модифицируем таблицу - добавим/удалим записи)

P.S. А задачка оказалась совсем не такой тривиальной...
 
 Top
valenok Модератор
Отправлено: 13 Апреля, 2007 - 22:30:18
Post Id



Здесь могла бы быть ваша реклама


Покинул форум
Сообщений всего: 4574
Дата рег-ции: Июль 2006  
Откуда: Israel


Помог: 3 раз(а)




mysql' овский RAND() возвращает число от 0 до 1
Для того наш rand я и поделил на 10 000


-----
Truly yours, Sasha.
 
My status
 Top
evgenijj
Отправлено: 13 Апреля, 2007 - 22:37:03
Post Id



Участник


Покинул форум
Сообщений всего: 1212
Дата рег-ции: Авг. 2006  
Откуда: Москва


Помог: 10 раз(а)




valenok пишет:
mysql' овский RAND() возвращает число от 0 до 1
Для того наш rand я и поделил на 10 000

Да, я понял. Но суть дела это не меняет - нельзя сортировать записи по константе 0.1234
SELECT * FROM `table` WHERE `char`='A' AND `num`=1 ORDER BY 0.1234 LIMIT 1
Выражение ORDER BY 0.1234 не имеет смысла - запросы
SELECT * FROM `table` WHERE `char`='A' AND `num`=1 ORDER BY 0.1234 LIMIT 1
SELECT * FROM `table` WHERE `char`='A' AND `num`=1 LIMIT 1
вернут одинаковые результаты.
 
 Top
valenok Модератор
Отправлено: 13 Апреля, 2007 - 22:43:55
Post Id



Здесь могла бы быть ваша реклама


Покинул форум
Сообщений всего: 4574
Дата рег-ции: Июль 2006  
Откуда: Israel


Помог: 3 раз(а)




Давай тогда ещё раз.

Что у нас происходит когда мы выполняем следующий запрос: ?
SELECT * FROM `table` WHERE `char`='A' AND `num`=1 ORDER BY RAND() LIMIT 1


-----
Truly yours, Sasha.
 
My status
 Top
evgenijj
Отправлено: 13 Апреля, 2007 - 22:47:50
Post Id



Участник


Покинул форум
Сообщений всего: 1212
Дата рег-ции: Авг. 2006  
Откуда: Москва


Помог: 10 раз(а)




Я еще спросить хотел. По поводу разбить талицу на "кусочки".

Вот, положим, у меня есть таблица, где хранится информация о продукции некоторой фирмы. Содержит 15000 записай. Я ее разбил на три - по 5000 записей в каждой. Я вроде слышал, что для MySQL это полезно. Но как работать с этими таблицами?

Пока таблица была одна, я мог составить запрос для получения одной записи
SELECT title, description, price, image FROM products WHERE id_product=1001

А как быть, если я одну таблицу разбил на три? Составлять запрос типа
SELECT title, description, price, image FROM products1 WHERE id_product=1001
UNION
SELECT title, description, price, image FROM products2 WHERE id_product=1001
UNION
SELECT title, description, price, image FROM products3 WHERE id_product=1001

(Добавление)
valenok пишет:
Давай тогда ещё раз.
Что у нас происходит когда мы выполняем следующий запрос: ?
SELECT * FROM `table` WHERE `char`='A' AND `num`=1 ORDER BY RAND() LIMIT 1

Я так понимаю, что из таблицы выбираются записи, удовлетворяющие условию WHERE `char`='A' AND `num`=1. При этом, для каждой записи высисляется значение RAND() и по нему идет сортировка
 
 Top
valenok Модератор
Отправлено: 13 Апреля, 2007 - 22:57:16
Post Id



Здесь могла бы быть ваша реклама


Покинул форум
Сообщений всего: 4574
Дата рег-ции: Июль 2006  
Откуда: Israel


Помог: 3 раз(а)




Нет, таким образом у тебя выходит что у тебя три таблицы по 5000 строк

первая таблица где товары относятся к категории мебели,
вторая таблица для товаров для кухни
и третяя таблица для товаров электро-приборов

Все три таблицы выглядят одинаково
Id_product | title | description | price

Теперь пользователь выбирает в магазине товар, жмёт добавить в корзину и в корзину добавляется id_product и category

А информация о товаре в БД будет лежать тут:
SELECT * FROM `table_of_".$category."` WHERE `product_id`=$id

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




(Добавление)
Цитата:
Я так понимаю, что из таблицы выбираются записи, удовлетворяющие условию WHERE `char`='A' AND `num`=1. При этом, для каждой записи высисляется значение RAND() и по нему идет сортировка


Дело в том что в 15 000 строковой таблице будет слишком много строк удовлетворяющих условие Char = A & num = 1 , поэтому системных ресурсов для вычисления и запоминания, а потом сортировки по этому числу - уходить будет очень много.

Можно ещё сделать чтото вроде такого:
SELECT * FROM `table` WHERE `char`='A' AND `num`=1 AND `id`=$rnd
и повторять эту комбинацию циклом while пока из базы чтото не выберется.
Мне кажется что при 15 000 строковой таблице, цикл долго крутится не будет, потому что шанс что такой id найдётся достаточно велик.
И системных ресурсов тратится будет меньше. Хотя цикл может в холостую работать и работать и так и не наткнутся очень быстро на подходящую запись..



-----
Truly yours, Sasha.
 
My status
 Top
evgenijj
Отправлено: 13 Апреля, 2007 - 23:16:34
Post Id



Участник


Покинул форум
Сообщений всего: 1212
Дата рег-ции: Авг. 2006  
Откуда: Москва


Помог: 10 раз(а)




Цитата:
первая таблица где товары относятся к категории мебели,
вторая таблица для товаров для кухни
и третяя таблица для товаров электро-приборов

Это мне понятно. Но так получается - мы искусственно усложняем структуру БД. Создаем дополнительные таблицы, хотя с точки зрения решения задачи в них нет необходимости. Ведь для хранения информации о структуре каталога продукции достаточно двух таблиц (даже одной - но получится нерациональное расходование полей). Я здесь провожу аналогию с файловой системой - есть каталоги (директории) и есть файлы (почему я говорю - достаточно одной таблицы - потому что директория - это тоже файл, только особого вида).

Цитата:

Таблица CATEGORIES:

1;0;Извещатели охранные;1
2;0;Извещатели пожарные;2
3;0;Приборы приемно-контрольные;3
6;1;Извещатели охранные магнитоконтактные;1
7;1;Извещатели охранные электроконтактные;2
8;1;Извещатели охранные ударноконтактные;3
9;2;Извещатели пожарные тепловые;1
10;2;Извещатели пожарные дымовые;2
11;2;Извещатели пожарные комбинированные;3
17;3;Приборы приемно-контрольные охранные;1
18;3;Приборы приемно-контрольные пожарные;2
19;3;Приборы приемно-контрольные охранно-пожарные;3

Таблица PRODUCTS:

1;6;Извещатель охранный магнитоконтактный ИО 102-2;Технические характеристики ИО 102-2;1
2;6;Извещатель охранный магнитоконтактный ИО 102-4;Технические характеристики ИО 102-4;2
3;6;Извещатель охранный магнитоконтактный ИО 102-14;Технические характеристики ИО 102-14;3
4;7;Извещатель охранный электроконтактный ИО 201-1;Технические характеристики ИО 201-1;1
5;7;Извещатель охранный электроконтактный ВПК 2112;Технические характеристики ВПК 2112;2
6;8;Извещатель охранный ударноконтактный "Окно-4";Технические характеристики "Окно-4";1
7;8;Извещатель охранный ударноконтактный "Окно-5";Технические характеристики "Окно-5";2
8;8;Извещатель охранный ударноконтактный "Окно-6";Технические характеристики "Окно-6";3
9;9;Извещатель пожарный тепловой ИП 114-01;Технические характеристики ИП 114-01;1
10;9;Извещатель пожарный тепловой ИП 101-1A;Технические характеристики ИП 101-1A;2
11;9;Извещатель пожарный тепловой ИП 101-30;Технические характеристики ИП 101-30;3
12;10;Извещатель пожарный дымовой ИП 212-3СМ;Технические характеристики ИП 212-3СМ;1
13;10;Извещатель пожарный дымовой ИП 212-18СИ;Технические характеристики ИП 212-18СИ;2
14;11;Извещатель пожарный комбинированный ИП 212/101-78-А1;Технические характеристики ИП 212/101-78-А1;1
15;11;Извещатель пожарный комбинированный ИП 212/101-18 А3R1;Технические характеристики ИП 212/101-18 А3R1;2


В этих двух таблицах я могу хранить каталоги продукции 2, 3, 10, 20 разных фирм (одно условие - придется добавить дополнительное поле - идентификатор фирмы, которой принадлежит категория или товар).

Мне интересно знать, как разбить эти таблицы, если они слишком разростутся (или будут изначально велики)? Получается, я должен буду изменить все запросы к этой таблице (а точнее - уже к трем), если разобью ее на части?

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

Цитата:
Дело в том что в 15 000 строковой таблице будет слишком много строк удовлетворяющих условие Char = A & num = 1 , поэтому системных ресурсов для вычисления и запоминания, а потом сортировки по этому числу - уходить будет очень много.
Можно ещё сделать чтото вроде такого:
SELECT * FROM `table` WHERE `char`='A' AND `num`=1 AND `id`=$rnd
и повторять эту комбинацию циклом while пока из базы чтото не выберется.

Согласен. Единственно, что я бы еще сделал - попробовал все варианты и засек бы время на выплнение. Но это не дает никаких гарантий - потому как у разных хостеров может быть по-разному. У одного PHP и MySQL на одной машине, у другого - на разных. И т.п.

(Добавление)
Мне не спится. Поэтому продожу. Пусть у нас есть фирма, которая предоставляет услуги хостинга и одновременно - услуги создания сайтов. Каждый сайт, создаваемый этой фирмой имеет каталог продукции (может быть и с Интернет-магазином). Все сайты работают на одном движке. Вся информация о продукции этих фирм хранится в двух таблицах CATEGORIES и PRODUCTS. Чтобы не заморачиваться каждый раз с модификацией движка (передавая в запросы уникальный идентификатор фирмы id_firm), эта фирма создает в БД представления (view)
CREATE VIEW CATEGORIES_FIRM1 AS
SELECT * FROM CATEGORIES WHERE id_firm=1
CREATE VIEW PRODUCTS_FIRM1 AS
SELECT * FROM PRODUCTS WHERE id_firm=1

CREATE VIEW CATEGORIES_FIRM2 AS
SELECT * FROM CATEGORIES WHERE id_firm=2
CREATE VIEW PRODUCTS_FIRM2 AS
SELECT * FROM PRODUCTS WHERE id_firm=2

CREATE VIEW CATEGORIES_FIRM3 AS
SELECT * FROM CATEGORIES WHERE id_firm=3
CREATE VIEW PRODUCTS_FIRM3 AS
SELECT * FROM PRODUCTS WHERE id_firm=3

А потом достаточно создать файл конфигурации config.ini следующего содержания
define("CATEGORIES", "CATEGORIES_FIRM1");
define("PRODUCTS", "PRODUCTS_FIRM1");
для первой фирмы

define("CATEGORIES", "CATEGORIES_FIRM2");
define("PRODUCTS", "PRODUCTS_FIRM2");
для второй фирмы

и т.д.

А в самом движке при необходимости обращения к таблице товаров пишем
$query = "SELECT id_prd, title, description, price FROM ".PRODUCTS." WHERE id_prd=".$id_prd;
При этом для первой фирмы будет идти обращение к представлению PRODUCTS_FIRM1, для второй - к PRODUCTS_FIRM2 и т.д.

Вопрос, который я хотел задать - если таблица PRODUCTS становится слишком велика - как ее грамотно разбить на части и как к эти частям обращаться?
 
 Top
valenok Модератор
Отправлено: 14 Апреля, 2007 - 09:33:20
Post Id



Здесь могла бы быть ваша реклама


Покинул форум
Сообщений всего: 4574
Дата рег-ции: Июль 2006  
Откуда: Israel


Помог: 3 раз(а)




Цитата:
Вся информация о продукции этих фирм хранится в двух таблицах CATEGORIES и PRODUCTS.


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

Тогда будут три таблицы

table_for_firm1
Id_prd | Title | Description Price | category

table_for_firm2
Id_prd | Title | Description Price | category

table_for_firm3
Id_prd | Title | Description Price | category

Скрипту придётся передавать уже два параметра: фирму и id
и запрос будет:
PHP:
скопировать код в буфер обмена
  1. <?
  2. $query = "SELECT * FROM `table_for_firm".$_GET['firm']."` WHERE id_prd=".$id_prd;
  3.  
\n\n(Добавление)
Цитата:
Но так получается - мы искусственно усложняем структуру БД. Создаем дополнительные таблицы


Я так понял нам надо уменьшить по размерам основную, тоесть разбить её на более маленькие таблицы.


-----
Truly yours, Sasha.
 
My status
 Top
Страниц (2): [1] 2 »
Сейчас эту тему просматривают: 0 (гостей: 0, зарегистрированных: 0)
« Программирование на PHP »


Все гости форума могут просматривать этот раздел.
Только зарегистрированные пользователи могут создавать новые темы в этом разделе.
Только зарегистрированные пользователи могут отвечать на сообщения в этом разделе.
 



Powered by PHP  Powered By MySQL  Powered by Nginx  Valid CSS  RSS

 
Powered by ExBB FM 1.0 RC1. InvisionExBB