Змінюй хід війни! Допомагай ЗСУ!

помогите плз с запросом mysql

  • Автор теми Автор теми BAV_Lug
  • Дата створення Дата створення
Статус: Офлайн
Реєстрація: 19.03.2007
Повідом.: 2655
помогите плз с запросом mysql

Есть таблица следующего вида

id text
1 111
2 222
3 111
4 555
5 111

и т.д. (к цифрам в поле text не цепляйтесь, это я для примера)

нужно сделать выборку в которой будут все строки, но чтобы поле text повторялось например не более 2-х раз.
Т.е. в результате из примера должны быть все поля кроме id = 5 (или 1, или 3 - это не принципиально)

ЗЫ Нужен такой себе вариант DISTINCT с параметром (количество одинаковых записей)
 
курсорами
 
В mysql есть циклы и курсоры, с помощью которых можно считать количество одинаковых вхождений и отсеивать лишнее. Ничего проще в нетрезвую голову не приходит :)
 
Код:
select *
  from table
 where text in (select text
                  from table
                having count(id) < 3
                 group by text)
 
Код:
Po_mesty_kyda_ykagy
  Po_indeksam
  Zpobit_viborka(yslovie *)

Можно и так.
 
Код:
select *
  from table
 where text in (select text
                  from table
                having count(id) < 3
                 group by text)
да, только в мускуле
HAVING clause must come after any GROUP BY clause and before any ORDER BY clause.
поэтому работать будет так:
Код:
SELECT * 
FROM table 
WHERE text IN (
    SELECT text 
    FROM table 
    GROUP BY text 
    HAVING count(id) < 3
)
 
Код:
SELECT * 
FROM table 
WHERE text IN (
    SELECT text 
    FROM table 
    GROUP BY text 
    HAVING count(id) < 3
)
Похоже вы не поняли задачи.
В таком варианте в ответе вообще не будет строк у которых поле text повторяется более 2-х раз :(

Пришел к выводу, что ответ про использование хранимых процедур наиболее верный, но так как их не всегда можно использовать (а разрабатываю модуль для многократного использования), пришлось выгребать все, а потом уже подчищать с помощью php
 
***, лучше бы и не начинал - свербит как заноза в ******е.
Надеюсь, окончательный вариант:
Код:
SELECT MIN(t1.id) AS id_res, t1.text AS text_res FROM (SELECT * FROM nomore2 ORDER BY id) t1 
			GROUP BY text_res
	
UNION
(
		SELECT MIN(t2.id) AS id_res, t1.text AS text_res FROM (SELECT * FROM nomore2 ORDER BY id) t1 
			LEFT JOIN (SELECT * FROM nomore2 ORDER BY id) t2 ON (t2.id > t1.id AND t1.text = t2.text)
                        WHERE t2.id IS NOT NULL
			GROUP BY text_res
)
ORDER BY id_res

*** мозги сломал, но так и не понял как это работает :( Но работает! Не понял как сюда добавить выборку произвольного числа повторяющихся записей (а не 2).
 
пардон, я задачу читал по диагонали. просто увидел запрос, который явно в MySQL не выполнится и поправил чуть.. по задаче - решение от Lapsha таки работает, причем довольно быстро. но чтобы изменить кол-во одинаковых записей по-моему нужно делать нетривиальные изменения в запросе, доращивая его через unioun.
мне в голову пришло такое. скорее мысли вслух, чем решение.

можно создать таблицу
Код:
CREATE TABLE _t2 LIKE _t1
(_t1 - это оригинал)

поместить в неё по одной записи с уникальным text:
Код:
INSERT INTO _t2 SELECT * FROM _t1 GROUP BY text
а потом сделать нужное кол-во таких запросов (для задачи "не более двух одинаковых" - один):
Код:
INSERT INTO _t2 (
    SELECT * 
    FROM _t1 
    WHERE id NOT IN (SELECT id FROM _t2) 
    GROUP BY text
)
в конце вынуть все из _t2 и грохнуть её.

лучше было бы делать TEMPORARY TABLE, но тогда возникнет ошибка Can't reopen table в последнем запросе, мускул не позволяет в одном запросе два раза ссылаться на одну и ту же временную таблицу.

ну а так много вопросов остается. обычные таблицы видят все, значит надо давать какие-то уникальные имена, чтобы не пересекались. потом, что будет, если возникнет какая-то проблема и она вдруг не грохнется. транзакции тут вряд ли помогут, в мускуле create table не откатывается.

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

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


по поводу выгребания всей таблицы. это таки плохо, если она будет большой. но негодования Лапши по поводу клиента не понял. на клиента пойдет только результат работы пхп скрипта, вся таблица же туда не полетит. но вот серверу придется туго. есть ведь ещё лимиты на используемую пхп-скриптом память. и вообще, память физически ограничена.. ну и плюс тормоза.
 
А что плохого в банальной идее:
Код:
select distinct n0.* from nomore2 n0
where n0.id in (select limit 2 n1.id from nomore2 n1 where n1.txt = n0.txt order by n1.id asc)
 
Код:
select id
     , text
  from (select id
             , text
             , dense_rank() over(partition by text order by id) as rank_
          from test)
  where rank_ < 3
В Oracle это было бы так. C limit у balkauser идея хорошая
 
Назад
Зверху Знизу