URL-фрагменты (# бит) НЕ отправляются на сервер (или, по крайней мере, их не должно быть). Ваш браузер отправляет обычный запрос GET, минус # бит. Когда получен ответ на страницу и отобразится страница, ваш браузер автоматически прокручивается до этого идентификатора. Таким образом, ваша схема не будет работать.
Кроме того, я уверен, что вы не используете ReWrite правильно. Насколько я понимаю, это используется для сопоставления запрошенных активов с каким-либо местоположением физического диска, оно не выдаёт перенаправление.
Изменить: ReWrite может используется для выдачи переадресации с флагом [R], по комментарию @ Хакре ниже. Таким образом, в этом случае вы хотите перенаправить с / page / six на / page # six, что позволяет Apache не задушить #six, если я думаю, что работа.
Для этого требуется ряд подзапросов для ранжирования значений, их ограничения, затем выполнения суммы при группировке
@Rnk:=0;
@N:=2;
select
c.id,
sum(c.val)
from (
select
b.id,
b.bal
from (
select
if(@last_id=id,@Rnk+1,1) as Rnk,
a.id,
a.val,
@last_id=id,
from (
select
id,
val
from list
order by id,val desc) as a) as b
where b.rnk < @N) as c
group by c.id;
Нет, вы не можете LIMIT подзапросы произвольно (вы можете сделать это в ограниченной степени в новых MySQL, но не для 5 результатов для каждой группы).
Это запрос типа с групповым максимумом, что нетрудно сделать в SQL. Существуют различные способы для решения того, что может быть более эффективным для некоторых случаев, но для top-n вообще вы хотите посмотреть на ответ Билла на аналогичный предыдущий Вопрос.
Как и в большинстве решений этой проблемы, он может возвращать более пяти строк, если имеется несколько строк с тем же значением rate
, поэтому вам может потребоваться некоторое количество пост-обработки для проверки для этого.
для таких, как я, у которых были тайм-ауты. Я сделал следующее, чтобы использовать лимиты и что-то еще по определенной группе.
DELIMITER $$
CREATE PROCEDURE count_limit200()
BEGIN
DECLARE a INT Default 0;
DECLARE stop_loop INT Default 0;
DECLARE domain_val VARCHAR(250);
DECLARE domain_list CURSOR FOR SELECT DISTINCT domain FROM db.one;
OPEN domain_list;
SELECT COUNT(DISTINCT(domain)) INTO stop_loop
FROM db.one;
-- BEGIN LOOP
loop_thru_domains: LOOP
FETCH domain_list INTO domain_val;
SET a=a+1;
INSERT INTO db.two(book,artist,title,title_count,last_updated)
SELECT * FROM
(
SELECT book,artist,title,COUNT(ObjectKey) AS titleCount, NOW()
FROM db.one
WHERE book = domain_val
GROUP BY artist,title
ORDER BY book,titleCount DESC
LIMIT 200
) a ON DUPLICATE KEY UPDATE title_count = titleCount, last_updated = NOW();
IF a = stop_loop THEN
LEAVE loop_thru_domain;
END IF;
END LOOP loop_thru_domain;
END $$
он перебирает список доменов, а затем вставляет только ограничение 200 каждый
Вы можете использовать агрегированную функцию GROUP_CONCAT , чтобы получить все годы в один столбец, сгруппированный по id
и упорядоченный по rate
:
SELECT id, GROUP_CONCAT(year ORDER BY rate DESC) grouped_year
FROM yourtable
GROUP BY id
Результат:
-----------------------------------------------------------
| ID | GROUPED_YEAR |
-----------------------------------------------------------
| p01 | 2006,2003,2008,2001,2007,2009,2002,2004,2005,2000 |
| p02 | 2001,2004,2002,2003,2000,2006,2007 |
-----------------------------------------------------------
И тогда вы можете использовать FIND_IN_SET , который возвращает позицию первого аргумента во втором, например.
SELECT FIND_IN_SET('2006', '2006,2003,2008,2001,2007,2009,2002,2004,2005,2000');
1
SELECT FIND_IN_SET('2009', '2006,2003,2008,2001,2007,2009,2002,2004,2005,2000');
6
Используя комбинации GROUP_CONCAT
и FIND_IN_SET
и фильтрации по позиции, возвращаемой find_in_set, вы можете использовать этот запрос, который возвращает только первые 5 лет для каждого id:
SELECT
yourtable.*
FROM
yourtable INNER JOIN (
SELECT
id,
GROUP_CONCAT(year ORDER BY rate DESC) grouped_year
FROM
yourtable
GROUP BY id) group_max
ON yourtable.id = group_max.id
AND FIND_IN_SET(year, grouped_year) BETWEEN 1 AND 5
ORDER BY
yourtable.id, yourtable.year DESC;
См. скрипку здесь .
Обратите внимание, что если более чем одна строка может иметь одинаковую скорость, вы должны рассмотреть возможность использования GROUP_CONCAT (DISTINCT rate ORDER BY rate) в столбце скорости вместо столбца года .
Максимальная длина строки, возвращаемой GROUP_CONCAT, ограничена, поэтому это хорошо работает, если вам нужно выбрать несколько записей для каждой группы.
SET SESSION group_concat_max_len = <maximum length>;
. В случае OP не проблема (поскольку по умолчанию - 1024), но в качестве примера group_concat_max_len должен быть не менее 25: 4 (максимальная длина строки года) + 1 (символ разделителя), раз 5 (первые 5 лет). Строки усекаются, а не бросают ошибку, поэтому следите за предупреждениями, такими как 1054 rows in set, 789 warnings (0.31 sec)
.
– Timothy Johns
16 March 2018 в 00:35
Пожалуйста, попробуйте ниже хранимую процедуру. Я уже проверял. Я получаю правильный результат, но не используя groupby
.
CREATE DEFINER=`ks_root`@`%` PROCEDURE `first_five_record_per_id`()
BEGIN
DECLARE query_string text;
DECLARE datasource1 varchar(24);
DECLARE done INT DEFAULT 0;
DECLARE tenants varchar(50);
DECLARE cur1 CURSOR FOR SELECT rid FROM demo1;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
SET @query_string='';
OPEN cur1;
read_loop: LOOP
FETCH cur1 INTO tenants ;
IF done THEN
LEAVE read_loop;
END IF;
SET @datasource1 = tenants;
SET @query_string = concat(@query_string,'(select * from demo where `id` = ''',@datasource1,''' order by rate desc LIMIT 5) UNION ALL ');
END LOOP;
close cur1;
SET @query_string = TRIM(TRAILING 'UNION ALL' FROM TRIM(@query_string));
select @query_string;
PREPARE stmt FROM @query_string;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END
Принял некоторые работы, но я решил, что мое решение будет разделяться, так как оно кажется элегантным и довольно быстрым.
SELECT h.year, h.id, h.rate
FROM (
SELECT id,
SUBSTRING_INDEX(GROUP_CONCAT(CONCAT(id, '-', year) ORDER BY rate DESC), ',' , 5) AS l
FROM h
WHERE year BETWEEN 2000 AND 2009
GROUP BY id
ORDER BY id
) AS h_temp
LEFT JOIN h ON h.id = h_temp.id
AND SUBSTRING_INDEX(h_temp.l, CONCAT(h.id, '-', h.year), 1) != h_temp.l
Обратите внимание, что этот пример указан для целей вопроса и может быть легко модифицирован для других аналогичных целей.
Попробуйте следующее:
SET @num := 0, @type := '';
SELECT `year`, `id`, `rate`,
@num := if(@type = `id`, @num + 1, 1) AS `row_number`,
@type := `id` AS `dummy`
FROM (
SELECT *
FROM `h`
WHERE (
`year` BETWEEN '2000' AND '2009'
AND `id` IN (SELECT `rid` FROM `table2`) AS `temp_rid`
)
ORDER BY `id`
) AS `temph`
GROUP BY `year`, `id`, `rate`
HAVING `row_number`<='5'
ORDER BY `id`, `rate DESC;
Создайте виртуальные столбцы (например, RowID в Oracle)
table:
`
CREATE TABLE `stack`
(`year` int(11) DEFAULT NULL,
`id` varchar(10) DEFAULT NULL,
`rate` float DEFAULT NULL)
ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
`
data:
insert into stack values(2006,'p01',8);
insert into stack values(2001,'p01',5.9);
insert into stack values(2007,'p01',5.3);
insert into stack values(2009,'p01',4.4);
insert into stack values(2001,'p02',12.5);
insert into stack values(2004,'p02',12.4);
insert into stack values(2005,'p01',2.1);
insert into stack values(2000,'p01',0.8);
insert into stack values(2002,'p02',12.2);
insert into stack values(2002,'p01',3.9);
insert into stack values(2004,'p01',3.5);
insert into stack values(2003,'p02',10.3);
insert into stack values(2000,'p02',8.7);
insert into stack values(2006,'p02',4.6);
insert into stack values(2007,'p02',3.3);
insert into stack values(2003,'p01',7.4);
insert into stack values(2008,'p01',6.8);
SQL вот так:
select t3.year,t3.id,t3.rate
from (select t1.*, (select count(*) from stack t2 where t1.rate<=t2.rate and t1.id=t2.id) as rownum from stack t1) t3
where rownum <=3 order by id,rate DESC;
, если удалить предложение where в t3, оно выглядит следующим образом:
GET «TOP N Record» - > добавьте «rownum & lt; = 3» в where where (предложение where t3);
ВЫБЕРИТЕ «год» -> добавьте «МЕЖДУ 2000 И 2009» в разделе where ( где - положение t3);
SELECT year, id, rate
FROM (SELECT
year, id, rate, row_number() over (partition by id order by rate DESC)
FROM h
WHERE year BETWEEN 2000 AND 2009
AND id IN (SELECT rid FROM table2)
GROUP BY id, year
ORDER BY id, rate DESC) as subquery
WHERE row_number <= 5
Подзапрос почти идентичен вашему запросу. Только изменение добавляет
row_number() over (partition by id order by rate DESC)
ROW_NUMBER()
).
– ypercubeᵀᴹ
7 January 2013 в 18:06
Попробуйте следующее:
SELECT h.year, h.id, h.rate
FROM (SELECT h.year, h.id, h.rate, IF(@lastid = (@lastid:=h.id), @index:=@index+1, @index:=0) indx
FROM (SELECT h.year, h.id, h.rate
FROM h
WHERE h.year BETWEEN 2000 AND 2009 AND id IN (SELECT rid FROM table2)
GROUP BY id, h.year
ORDER BY id, rate DESC
) h, (SELECT @lastid:='', @index:=0) AS a
) h
WHERE h.indx <= 5;
Исходный запрос использовал пользовательские переменные и ORDER BY
в производных таблицах; поведение обоих причуд не гарантируется. Пересмотренный ответ следующим образом.
Вы можете использовать ранг бедного человека над разделом для достижения желаемого результата. Просто внешнее соединение таблицы с самим собой и для каждой строки подсчитайте количество строк lesser , чем оно:
SELECT testdata.id, testdata.rate, testdata.year, COUNT(lesser.rate) AS rank
FROM testdata
LEFT JOIN testdata AS lesser ON testdata.id = lesser.id AND testdata.rate < lesser.rate
GROUP BY testdata.id, testdata.rate, testdata.year
HAVING COUNT(lesser.rate) < 5
ORDER BY testdata.id, testdata.rate DESC
Обратите внимание, что:
Результат:
+------+-------+------+------+
| id | rate | year | rank |
+------+-------+------+------+
| p01 | 8.00 | 2006 | 0 |
| p01 | 7.40 | 2003 | 1 |
| p01 | 6.80 | 2008 | 2 |
| p01 | 5.90 | 2001 | 3 |
| p01 | 5.30 | 2007 | 4 |
| p02 | 12.50 | 2001 | 0 |
| p02 | 12.40 | 2004 | 1 |
| p02 | 12.20 | 2002 | 2 |
| p02 | 10.30 | 2003 | 3 |
| p02 | 8.70 | 2000 | 4 |
+------+-------+------+------+
WHERE rank <=5
? Впервые я не получаю 5 строк от каждого идентификатора, но после этого я могу получить, как вы сказали.
– Brenno Leal
1 August 2016 в 17:37
SET
(см. Первый запрос). Это необходимо.
– Salman A
1 August 2016 в 18:12
ORDER BY
в производной таблице может и часто игнорируется. Это побеждает цель. Эффективные групповые найдены здесь здесь .
– Rick James
10 February 2018 в 05:21
Следующая публикация: sql: selcting top N записей на группу описывает сложный способ достижения этого без подзапросов.
Он улучшает другие решения, предлагаемые здесь:
Это, однако, не очень. Хорошим решением было бы возможно, если в MySQL были включены функции Window (aka Analytic Functions), но это не так. В трюке, используемой в указанном сообщении, используется GROUP_CONCAT, который иногда описывается как «Функции окна для пользователя для MySQL».
Для меня что-то вроде
SUBSTRING_INDEX(group_concat(col_name order by desired_col_order_name), ',', N)
работает отлично. Нет сложного запроса.
например: get top 1 для каждой группы
SELECT
*
FROM
yourtable
WHERE
id IN (SELECT
SUBSTRING_INDEX(GROUP_CONCAT(id
ORDER BY rate DESC),
',',
1) id
FROM
yourtable
GROUP BY year)
ORDER BY rate DESC;