обращение к уже полученным результатам в запросе в том же запросе

Итак, предположим, у меня есть эта таблица с 4 столбцами:

id  content  parent   timestamp

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

Я хочу сделать следующее:

Выберите первые 50 строк из таблицы в следующем порядке:

for each row,

if(parent = 0){
  add row to resultset, ordered by timestamp
}
else if (parent != 0){
   if parent is in the list of rows already fetched so far by the query,
   add row to resultset, ordered by the timestamp
   otherwise, wait until the parent gets fetched by the query 
   (assuming it gets fetched at all since there we're only getting the first 50 rows) 
} 

эта логика упорядочения несколько сложна, и мне интересно, возможно ли это сделать с помощью оператора MYSQL ORDER BY в одном запросе БЕЗ необходимости прибегать к подзапросам? Может быть, мы могли бы установить и использовать переменные? Но как будет реализован оператор ORDER BY?


person pillarOfLight    schedule 06.05.2013    source источник
comment
Я почти уверен, что это невозможно с order by и довольно сложно даже с подзапросами. Извлечение поддерева из древовидной структуры будет иметь аналогичный псевдокод. А извлечение поддерева - сложная проблема.   -  person Gordon Linoff    schedule 07.05.2013
comment
это один на один родительский ребенок? это только на один уровень глубиной?   -  person mconlin    schedule 07.05.2013


Ответы (1)


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

Удалите любую старую версию процедуры и установите разделитель

DROP PROCEDURE IF EXISTS order_proc;
DELIMITER ;;

Начать писать процедуру

CREATE PROCEDURE order_proc()
BEGIN
DECLARE n INT DEFAULT 50;
DECLARE m INT DEFAULT 0;
DECLARE i INT DEFAULT 0;
DECLARE custom_limit INT DEFAULT 0;

DROP TABLE IF EXISTS pre_resultset;
CREATE TABLE pre_resultset LIKE input_data;
ALTER TABLE pre_resultset MODIFY id INT;
ALTER TABLE pre_resultset DROP PRIMARY KEY;
ALTER TABLE pre_resultset ADD COLUMN iid INT PRIMARY KEY NOT NULL AUTO_INCREMENT FIRST;

SELECT n INTO custom_limit;
Set SQL_SELECT_LIMIT = custom_limit;
INSERT INTO pre_resultset SELECT NULL,id, content, parent, timestamp FROM input_data WHERE parent = 0 ORDER BY timestamp;
Set SQL_SELECT_LIMIT = default;

DROP TABLE IF EXISTS unused_input_data;
CREATE TABLE unused_input_data LIKE input_data;
ALTER TABLE unused_input_data ADD null_col VARCHAR(1);
SELECT COUNT(*) FROM pre_resultset INTO m;
WHILE m<n DO 
  SELECT COUNT(*) FROM pre_resultset INTO m;
  TRUNCATE unused_input_data;
  INSERT INTO unused_input_data SELECT input_data.id, input_data.content, input_data.parent, input_data.timestamp, pre_resultset.id AS null_col FROM input_data LEFT OUTER JOIN pre_resultset on input_data.id = pre_resultset.id WHERE pre_resultset.id IS NULL ;

  SELECT n-m INTO custom_limit;
  Set SQL_SELECT_LIMIT = custom_limit;
  INSERT INTO pre_resultset SELECT NULL, unused_input_data.id, unused_input_data.content, unused_input_data.parent, unused_input_data.timestamp FROM unused_input_data JOIN pre_resultset WHERE unused_input_data.parent = pre_resultset.id ORDER BY unused_input_data.timestamp;
  Set SQL_SELECT_LIMIT = default;

  SELECT COUNT(*) FROM pre_resultset INTO i;
  SELECT (IF( i = m, n, i)) INTO m;
END WHILE;
SELECT id, content, parent, timestamp FROM pre_resultset AS resultset;
DROP TABLE IF EXISTS pre_resultset;
DROP TABLE IF EXISTS unused_input_data;
End;
;;

Поменять разделитель обратно

DELIMITER ;

Запустите процедуру

CALL order_proc();
person Mr Purple    schedule 07.05.2013