Почему некорректные результаты выборки при ORDER BY?

Здравствуйте.

Есть таблица, с двумя основными полями - uid и status
+------+--------+---------+
| id | uid | status |
+------+--------+---------+
| 1 | 1 | 1 |
| 2 | 1 | 1 |
| 3 | 1 | 0 |
| 4 | 3 | 0 |
| 5 | 3 | 0 |
| 6 | 4 | 0 |
| 7 | 4 | 1 |
| 8 | 4 | 0 |
| 9 | 4 | 1 |
| 10 | 4 | 0 |
| 11 | 5 | 0 |
| 12 | 5 | 1 |
+------+---------+---------+

Нужно сделать выборку id по определенным условиям (uid > n и status = 1)
НО нужно, чтобы возвращались все подходящие строки только для одного uid, который я заранее не знаю. Пример:
SELECT id FROM table WHERE uid > 0 AND status = 1
Мне нужны строки 1 и 2 только для uid 1, т.к. на него пришлось первое вхождение
Другой пример:
SELECT id FROM table WHERE uid > 1 AND status = 1
В данном случае нужны строки 7 и 9, т.к. первое вхождение по условию пришлось на uid 4 и у него 2 совпавших поля.

Пробую сделать при помощи переменной:
SET @uid:= NULL;
SELECT
	t.id,
	@uid := t.uid
FROM 
	table t
WHERE 
	t.uid > 0
	AND (@uid IS NULL OR t.uid = @uid) 
	AND t.status = 1


Возвращает то что нужно - 1 и 2
Все замечательно получилось, но когда применил данный способ в проекте, вылезла неприятная вещь - запрос возвращает чушь после применения сортировки ORDER BY t.uid ASC;
Без сортировки не обойтись никак. Если в таблице значения uid идут не по порядку (что в проекте - обычное дело):
+------+--------+---------+
| id | uid | status |
+------+--------+---------+
| 5 | 3 | 0 | <сначала 3
| 6 | 4 | 0 |
| 7 | 4 | 1 |
| 8 | 4 | 0 |
| 9 | 4 | 1 |
| 10 | 4 | 0 |
| 11 | 5 | 1 |
| 12 | 5 | 1 |
| 13 | 6 | 0 |
| 14 | 1 | 1 | <затем 1
| 15 | 1 | 1 |
| 16 | 4 | 1 |
+------+---------+---------+

То при том же запросе с t.uid > 0 вернет строки для uid = 4, т.к. она стоит раньше, а записи для uid = 1 не вернет НИКОГДА.

После модификации запроса и добавления к нему ORDER BY t.uid ASC по логике должно вернуть 14 и 15 строки, но результат оказывается непредсказуем:
Возвращает по порядку 14, 15, 7, 9, 16, 11, 12 - хотя на первых двух результатах ему следовало остановиться.

В чем может быть проблема? Или может я некорректный способ выбрал для реализации данной задачи?
  • Вопрос задан
  • 2689 просмотров
Пригласить эксперта
Ответы на вопрос 3
SELECT t1.id, t1.uid FROM t1 
	WHERE  t1.status = 1 AND  t1.uid = (SELECT uid 
			FROM t1 
				WHERE t1.uid>0
				AND t1.status = 1 
				LIMIT 1
				ORDER BY t.uid ASC
					)
Ответ написан
Комментировать
@Vampiro
я бы делал приблизительно в этом направлении:
select id from table where uid=(select min(uid) from table where uid>N and status=1 ) and status=1
Ответ написан
Комментировать
@brom_portret
Я, к сожалению, с MySQL дело имел давно, и не так, чтобы много, но:

1) Наверное, можно создать индекс на поле uid и указывать его при выборке.
Попробуйте, ради интереса:
CREATE idx_uid ON table;

SET @uid:= NULL;
SELECT
    t.id,
    @uid := t.uid
FROM 
    table t
FORCE INDEX (idx_uid)
WHERE 
    t.uid > 0
    AND (@uid IS NULL OR t.uid = @uid) 
    AND t.status = 1


2) Вместо подзапроса в WHERE я бы использовал INNER JOIN к подзапросу.
SELECT 
    t.id, t.uid
FROM table AS t
INNER JOIN (
    SELECT uid FROM table 
    WHERE 
       uid > 0 AND status=1 
    ORDER BY uid LIMIT 1
) AS tt ON t1.uid = tt.uid;
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы