Забыли пароль?
Запросите новый здесь.

Автор темы: grungestranger
ID темы: 2335
Информация:
Тема содержит 30 сообщения, была просмотрена 20023 раз.
Просмотр темы
PHP-Fusion Russia » Веб-разработка » MySQL
 Распечатать тему
Зад. по MySQL
grungestranger
Допустим, есть таблица:

Таблица t1
id type
1- 1
2- 1
3- 1
4- 2
5- 2
6- 2
7- 3
8- 3
9- 3
10 4

Как сделать выборку, чтобы строк с каждым типом было, например, не больше 2 ?
То есть получить:

id type
1- 1
2- 1
4- 2
5- 2
7- 3
8- 3
10 4
 
Web
spiker
Так не пойдёт?

Загрузить источник  GeSHi: PHP
  1. $types = array('1' => 0, '2' => 0, '3' => 0, '4' => 0);
  2.  
  3. $result = dbquery("SELECT id, type FROM ".DB_PREFIX."type ORDER BY id ASC");
  4. while (list($id, $type) = dbarraynum($result)):
  5. $types[$type]++;
  6. if (array_key_exists($type, $types) and $types[$type] <= 2) echo $id.' - '.$type.'<br />';
  7. endwhile;
Добавлено за 0.030 секунд, используя GeSHi 1.0.8.10
 
grungestranger
spiker написал:

Так не пойдёт?

Загрузить источник  GeSHi: PHP
  1. $types = array('1' => 0, '2' => 0, '3' => 0, '4' => 0);
  2.  
  3. $result = dbquery("SELECT id, type FROM ".DB_PREFIX."type ORDER BY id ASC");
  4. while (list($id, $type) = dbarraynum($result)):
  5. $types[$type]++;
  6. if (array_key_exists($type, $types) and $types[$type] <= 2) echo $id.' - '.$type.'<br />';
  7. endwhile;
Добавлено за 0.028 секунд, используя GeSHi 1.0.8.10


Неет)) Надо только через sql

SELECT * FROM t1 WHERE type = '1' ORDER BY id LIMIT 2
UNION ALL (SELECT * FROM t1 WHERE type = '2' ORDER BY id LIMIT 2)
UNION ALL (SELECT * FROM t1 WHERE type = '3' ORDER BY id LIMIT 2)
...

Но так как подразумевается, что типов может быть бесконечно...
Нужно что-то другое.
 
Web
spiker
Неет)) Надо только через sql

Кому надо то? Поспорил что ль с кем?
Цель какая — сделать, чтоб работало? Или сломать мозг как впихнуть 100500 UNION ALL'ов в SQL запрос?
 
grungestranger
spiker написал:

Неет)) Надо только через sql

Кому надо то? Поспорил что ль с кем?
Цель какая — сделать, чтоб работало? Или сломать мозг как впихнуть 100500 UNION ALL'ов в SQL запрос?


Это задачка, цель которой - выяснить, можно так сделать или нет. И union all тут не при чем, с ними так не получится.

Тут надо делать, типа:

SELECT * FROM (
SELECT *, [здесь как-то присваивать 1 только первым двум строкам типа, возможно с помощью переменных] AS x FROM t1
ORDER BY t1.type, id
) temp_table
WHERE x = '1'
ORDER BY t1.type, id
Изменил(а) grungestranger, 08.10.2014 13:24
 
Web
spiker
Ну не знаю. Я бы заморачиваться бы не стал.
Простой вариант я написал.
Ну если, неохота вбивать в массив, или не знаешь значения типов, можно "зацепить" уникальные отдельным SQL запросом.

Как то так
Загрузить источник  GeSHi: PHP
  1.  
  2. $types = array();
  3.  
  4. $result = dbquery("SELECT DISTINCT type FROM ".DB_PREFIX."type");
  5. while (list($type) = dbarraynum($result)):
  6. $types[] = $type;
  7. endwhile;
  8.  
  9. $a = $b = array();
  10. foreach ($types as $key=>$value) {$a[] = $value; $b[] = 0;}
  11. $types = array_combine($a, $b);
  12.  
  13.  
  14.  
  15.  
  16. $result = dbquery("SELECT id, type FROM ".DB_PREFIX."type ORDER BY id ASC");
  17. while (list($id, $type) = dbarraynum($result)):
  18. $types[$type]++;
  19. if (array_key_exists($type, $types) and $types[$type] <= 2) echo $id.' - '.$type.'<br />';
  20. endwhile;
  21.  
Добавлено за 0.033 секунд, используя GeSHi 1.0.8.10
 
grungestranger
spiker, Такие запросы нужно делать без php, потому что иначе нельзя сделать постраничную разбивку данных. (Точнее можно, но это будет во много раз дольше)

Вот такой вариант

SELECT @i := 0;
SELECT @j := 0;

SELECT * FROM (
SELECT *, IF (@i != t1.type, @j := 0, @j := @j + 1) AS q, IF (@j < 2, 1, 0) AS x, IF (@i != t1.type, @i := t1.type, 0) AS w FROM t1
ORDER BY t1.type, id
) temp_table
WHERE x = '1'
ORDER BY t1.type, id

должен был бы работать но, нет, видимо связано с подзапросом...

SELECT @i := 0;
SELECT @j := 0;
SELECT *, IF (@i != t1.type, @j := 0, @j := @j + 1) AS q, IF (@j < 2, 1, 0) AS x, IF (@i != t1.type, @i := t1.type, 0) AS w FROM t1
ORDER BY t1.type, id

а вот так работает, то есть ко всем нужным строкам в поле x ставит 1

Но как сделать, чтобы это было подзапросом, и чтобы из него выбирать....
Изменил(а) grungestranger, 08.10.2014 13:25
 
Web
spiker
spiker, Такие запросы нужно делать без php, потому что иначе нельзя сделать постраничную разбивку данных. (Точнее можно, но это будет во много раз дольше)

Чё там сложного не пойму. перевести в массив и разбить на страницы..

Скачать исходники  Код
$types = array();

 $result = dbquery("SELECT DISTINCT type FROM ".DB_PREFIX."type");
    while (list($type) = dbarraynum($result)):
        $types[] = $type;
     endwhile;

   $a = $b = array();
   foreach ($types as $key=>$value) {$a[] = $value; $b[] = 0;}   
   $types = array_combine($a, $b);
   
   

 $id = $type = array();
 $result = dbquery("SELECT id, type FROM ".DB_PREFIX."type ORDER BY id ASC");
    while (list($key, $value) = dbarraynum($result)):
        $types[$value]++;
        if (array_key_exists($value, $types) and $types[$value] <= 2) {
         $id[] = $key;
         $type[] = $value;
         }
     endwhile;
   
   
   
   $per_page = 2; // Кол-во на страницу
   $array = array_combine($id, $type);
   $pages = array_chunk($array, $per_page, TRUE);
   
   
    if (!isset($_GET['rowstart']) || !isnum($_GET['rowstart'])) { $_GET['rowstart'] = 0; }
    foreach ($pages[$_GET['rowstart']] as $key=>$value)  echo $key.' - '.$value.'<br />';
 
    echo "<div align='center' style='margin-top:5px;'>\n".makepagenav($_GET['rowstart'], 1, count($pages), 3, FUSION_SELF."?")."\n</div>\n";


 
grungestranger
spiker - это не сложно)) это будет выполняться НАМНОГО ДОЛЬШЕ!!!

Объединено 08.10.2014 11:57:
Вот так работает

SET @i := 0;
SET @j := 0;

SELECT * FROM (
SELECT *, IF (@i != t1.type, @j := 0, @j := @j + 1) AS q, IF (@j < 2, 1, 0) AS x, IF (@i != t1.type, @i := t1.type, 0) AS w FROM t1
ORDER BY t1.type, id
) temp_table
WHERE x = '1'
ORDER BY t1.type, id
Изменил(а) grungestranger, 08.10.2014 13:25
 
Web
spiker
Ну... нам простым смертным вас — эстетов не понять.
 
Rush
намного это на одну миллионную секунды, лол?
 
Web
grungestranger
Rush

)) Ну ты даешь))

Представь, у тебя есть миллион строк, и тебе надо разбить их по 10 штук на каждой странице)

SQL справится с этим быстро, и с помощью LIMIT выдаст тебе нужные 10 строк.

Ну и, например, тебе надо выбрать последние 10 строк, чтобы сделать это с помощью php, тебе придется весь миллион строк прогонять в массиве, плюс со всякими дополнительными запросами)). Что будет НАМНОГО ДОЛЬШЕ))
 
Web
spiker
Ух ты.. миллион строк.
Ну где результат танцев с бубном?
Выкладывай, будем смотреть.
С постраничной навигаций bs

ЗЫ Массив да, будет тормозить (при таком объёме).
Для постраничной навигации ещё же надо подсчитать общее количество на каких то условиях отсева ненужных строк.
Изменил(а) spiker, 08.10.2014 13:33
 
grungestranger
ЗЫ Массив да, будет тормозить (при таком объёме).
Для постраничной навигации ещё же надо подсчитать общее количество на каких то условиях отсева ненужных строк.
- вот вот

spiker

Ну у меня то не миллион строк, конечно, но надо всегда на такое рассчитывать))

Ну а мне, действительно нужно для работы) Интернет магазин, грубо говоря, есть типы и в них продукты, и надо выводить все это подряд, но в каждом типе выводить не более 8 первых продуктов. И все это с страничной навигацией, которая зависит именно от количества продуктов.
 
Web
Razor
Ну чувак ты и наворотил..
Скачать исходники  Код

SET SESSION group_concat_max_len = 2;
select type, group_concat(distinct id)  from test GROUP BY type DESC;




Не благодари:)
p/s
но предыдущее решение выглядит круто..
Изменил(а) Razor, 08.10.2014 14:21
Sr. Software developer
plesk.com
 
grungestranger
Razor написал:

Ну чувак ты и наворотил..
Скачать исходники  Код

SET SESSION group_concat_max_len = 2;
select type, group_concat(distinct id)  from test GROUP BY type DESC;




Не благодари:)
p/s
но предыдущее решение выглядит круто..


Этот запрос выбирает совсем не то, о чем здесь говорилось))

Его результат

type----group_concat(distinct id)
4--------10
3--------9,8,
2--------6,5,
1--------3,2,
 
Web
Razor
Всё правильно, во второй колонке как раз айдишники, а в первой группа к которой они принадлежат.
Дальше юзаешь explode(',',$id);
и получаешь собственно айдишники..

Объединено 08.10.2014 15:25:
Чтоб было ещё более наглядно...
Запрос : SET SESSION group_concat_max_len = 2;
select type, group_concat(distinct id) as ids from test GROUP BY type DESC;

Загрузить источник  GeSHi: PHP
  1.  
  2. $arr = array();
  3. foreach ($query as $v) {
  4. $ids = explode(',',$v['ids']);
  5.  
  6. $arr[$v['type']] = $ids;
  7.  
  8. }
  9. var_dump($arr);
  10.  
Добавлено за 0.036 секунд, используя GeSHi 1.0.8.10

На выходе получим массив ключ(тип) => значение(массив айдишников)

Вот пруф, тестил, всё работает.
Выглядит гораздо более лаконично и работает не менее быстро.
А вообще если вы используете подобные запросы, в первую очередь задайте себе вопрос, возможно в вашем приложении неправильно построена структура базы данных или логика работы приложения, т.к. подобные конструкции лучше обходить стороной.
Изменил(а) Razor, 08.10.2014 15:51
Sr. Software developer
plesk.com
 
grungestranger
Razor

Задача была получить то, что написано в первом посте, без использования php.

Во-вторых твой вариант нерабочий

Потому что нам нужно получить первые 2 строки (в нашем случае по id) для каждого типа, у тебя же выводятся не первые.
Чтобы в любом случае выводились первые, нужен подзапрос, и выглядеть будет так:

SET SESSION group_concat_max_len = 2;

SELECT type1, group_concat(id) FROM (
SELECT t1.type AS type1, id FROM t1 ORDER BY id
) temp_table
GROUP BY type1
ORDER BY type1

Во вторых:

group_concat_max_len задает максимальную длину строки

ты пробовал менять group_concat_max_len = 2 ? что выводит? полную чушь

в третьих максимальная длина этой получено строки не может быть длиннее 1024 символа
Изменил(а) grungestranger, 08.10.2014 16:08
 
Web
Razor
Почему не рабочий то?
Давай на пальцах..
Смотри без использования php..
структура таблицы
запрос
Внимательно посмотри на структуру таблицы, на айдишники и на порядок их вывода на 2 сриншоте(1,2,4,5,8,9). Выводятся по порядку и как раз первые два.
Получаю я их без php, как видишь..
меняю max_len... смотрим... вуаля, не полная чушь..
пруф
Изменил(а) Razor, 08.10.2014 16:11
Sr. Software developer
plesk.com
 
grungestranger
Ты получаешь только id-шники, да и то, ты не сможешь получать уже ничего когда id станут двухзначными или трехзначными, в конце остаются запятые. А надо получать строки, а не только id.

Внимательно посмотри на структуру таблицы, на айдишники и на порядок их вывода на 2 сриншоте(1,2,4,5,8,9). Выводятся по порядку и как раз первые два.


если таблица будет перемешена, то ты будешь получать не первые значения))


меняю max_len... смотрим... вуаля, не полная чушь..
пруф


ну и что это дало, ты поставил 1000, а ты поставь 3, и чтобы было по 3 значения, и учитывая, что значения могут быть и двухзначными и трехзначными.
 
Web

Поделиться этой темой
Социальные закладки: Vkontakte Odnoklassniki Mail.ru Facebook Google Tweet This
URL:
BBcode:
HTML:

Перейти на форум:
Похожие темы
Топ 5 пользователей форума
Alex Alex (1,211)   Zaxap Zaxap (1,089)   Vova Vova (877)   Pisatel Pisatel (678)   util util (666)