2013-06-07 2 views
3

Я работаю с общей панелью данных, которая может иметь множество различных запросов, подающих эту панель. Они могут быть простыми запросами, которые выбираются из таблицы или представления, или сложными, которые пользователи определяют со сложными объединениями и другими выражениями. Я пытаюсь изменить мою панель данных, чтобы, если пользователь выбирает запись, сортирует таблицу, я нахожу страницу, на которой сейчас записывается запись, переместится на нее, а затем повторно выберите запись.MySql: найдите номер строки конкретной записи

У меня есть большая часть этого, но у меня проблемы с поиском номера страницы для перехода. Я изначально просто зацикливал строки на панели данных, но из-за пейджинга это оказалось очень неэффективным, чем больше номер страницы. Вместо этого я решил сделать это прямо через SQL, где я сейчас застрял.

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

Исходный запрос был

select * 
from table_a 
order by column_c desc 

И измененный запрос с номерами строк стал

select *, (@rownum := @rownum + 1) as rownum 
from 
(select @rownum := 0) rn 
, (
    select * 
    from table_a 
    order by column_c desc 
) data 

На данный момент я выбрать все записи. Затем я обернут приведенный выше запрос и выбрал минимальную строку, в которой запись согласованной выбранный мой рекорд как так

select min(rownum) 
from 
( 
    select *, (@rownum := @rownum + 1) as rownum 
    from 
    (select @rownum := 0) rn 
    , (
    select * 
    from table_a 
    order by column_c desc 
) data 
) wrapper 
where 
    primarykeyfield1 = ? 
    and primarykeyfield2 = ? 

Сначала это казалось, работает. Однако во время тестирования я обнаружил, что если бы я отсортировал поле, которое было недостаточно уникальным (например, 1000 записей имели одинаковое значение в этом поле), он переставал работать. Я сделал рытье и обнаружил, что вышеприведенный код будет возвращать разные rownum каждый раз, когда запрос выполняется.

После некоторого дополнительного копания, я обнаружил, что если были выполнить следующий запрос, я хотел бы получить результаты, которые я хотел

select * from table_a order by column_c 

Но если я просто завернутые этот запрос, как так

select * from (select * from table_a order by column_c) 

Порядок записей сильно менялся каждый раз, когда я запускал запрос. Это объясняет, почему строка num менялась, потому что она фактически меняется. Однако я не могу понять, почему заказ изменился бы просто путем обертывания запроса. Я сделал это в других системах баз данных, поэтому я предполагаю, что это связано с MySql, но я не смог найти информацию, чтобы объяснить, почему. Моя презумпция заключается в том, что порядок by либо не применяется при завершении запроса таким образом, либо поведение не так, как ожидалось.

Далее я попытался переместить количество RowNum непосредственно в основной/базовый запрос как так

select *, (@rownum := @rownum + 1) as rownum 
from (select @rownum := 0) rn, table_a 
order by column_c desc 

Выполнение этого запроса само по себе создает правильные номера строк. Однако, так как мне нужно, чтобы найти конкретную строку Num выбранной записи я должен обернуть этот запрос, как так

select min(rownum) 
from (
    select *, (@rownum := @rownum + 1) as rownum 
    from (select @rownum := 0) rn, table_a 
    order by column_c desc 
) data 
where 
    primarykeyfield1 = ? 
    and primarykeyfield2 = ? 

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

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

Обратите внимание, что я использую min для окончательного внешнего запроса, потому что в конечном итоге пользователь может выбрать несколько строк, и все эти строки входят в конечное предложение where. Поэтому я хочу найти наименьшее число строк и перейти на эту страницу.

+0

Рассмотрите упрощение своей проблемы. Никто не хочет читать все это! – Strawberry

+0

Также укажите схему базы данных и, желательно, некоторые данные примера. –

ответ

0

Это много, чтобы принять участие, поэтому позвольте мне попытаться сломать проблему. Сначала вам кажется, что вам нужно решить проблему непредсказуемого упорядочения строк.

Мое предложение для вас заключается в том, что вы всегда сортируете по уникальному первичному ключу таблицы в некотором роде. Если пользователь просматривает страницу в оригинальном «несортированном» (по выбору пользователя, что есть) порядок, до сих пор используют свой род как:

SELECT * 
FROM table 
ORDER BY primary_key ASC 
LIMIT 0, [page limit value] 

Когда пользователь выбирает для сортировки по какой-либо другой области, убедитесь, что первичным Ключевое поле до сих пор используется в этом роде, как это:

SELECT * 
FROM table 
ORDER BY sort_field [ASC|DESC], primary_key ASC 
LIMIT 0, [page limit value] 

Это будет гарантировать вам тот же порядок, на несколько вызовов в том же роде, даже когда мощность поля сортируется пользователем, является низкой (т.е. не много различные значения), поскольку у вас всегда есть уникальное поле первичного ключа, чтобы указать порядок, когда значения в отсортированном поле равны.

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

Вы можете сначала определить это Ее смещение в новом виде следующий образом:

SELECT count(*) 
FROM table 
WHERE 
    sort_field <= (SELECT sort_field FROM table WHERE primary_key = ?) 
    AND primary_key < ? 

Это говорит вам, количество строк (в том числе выбранной строки) в наборе данных перед вашей выбранной строкой (ваше смещение) , Обратите внимание, что это для восходящей сортировки. Вам, очевидно, нужно будет использовать >= и > для случая нисходящей сортировки.

Вы затем использовать это смещение в ранее показанном запросе, например:

SELECT * 
FROM table 
ORDER BY sort_field [ASC|DECS], primary_key ASC 
LIMIT [offset], [page limit value] 

Если вы хотите, фактическое число страниц, что строка находится на (например, если вы хотите, понятие фиксированной страницы (где выбранная строка может отображаться или не отображаться в первой строке), вы также можете легко вычислить ее, разделив смещение на предельное значение страницы и округляя результат. Затем вы разделили бы «страницу смещения» на «предел страницы», для определения значения смещения, которое должно использоваться.

Так что скажите, что строка имеет общее смещение 125, а ограничение страницы - 50. Вот псевдокод

selected_row_offset = 125; 
page_limit = 50; 
offset_page = floor(selected_row_offset/page_limit); 
query_offset = offset_page * page_limit; 

И ваш запрос будет

SELECT * 
FROM table 
ORDER BY sort_field [ASC|DECS], primary_key ASC 
LIMIT [query_offset], [page limit value] 

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

3

Моя цель решается :) Итак, я вывешиваю здесь, если кто-то считает его подходящим:

SELECT d.myRowSerial 
FROM (
    SELECT *, @rownum:[email protected] + 1 AS myRowSerial 
    FROM myTable, (SELECT @rownum:=0) AS nothingButSetInitialValue 
    WHERE 1=1 -- Optional: filter if required, otherwise, omit this line; 
    ORDER BY AnyColumn -- Apply the order you like; 
) d 
WHERE d.myColumn = 'Anything'; -- If you like to limit it to only 
-- for any specific row(s), similar to the *MAIN query. 

Если вам нужен номер страницы, которые тоже могут быть использованы для определения значения смещения для пагинации, то просто изменить 1-я строка сверху, как это:

SELECT d.myRowSerial, FLOOR((d.myRowSerial-1)/10) AS pageNumber 
-- Say, 10 is per page; 

Вы будете иметь PageNumber == 0 для страницы 1 и PageNumber == 1 на странице 2 и так далее .....

0

Спасибо Reza Mamun, Я разработал способ поставить номера записей таким образом, что даже если вы получите данные с использованием лимита, вы точно узнаете, какой номер соответствует записи.

SELECT @rownum:[email protected] + 1 AS myRowSerial, 
* 
FROM myTable, (SELECT @rownum:=0) AS nothingButSetInitialValue 
LIMIT 0,10 

Это даст вам номера записей. Теперь осуществить ограничение, проходят в том же пределе, например LIMIT 10,10, затем установите ROWNUM в начале предела т.е. 10 в FROM п

Модифицированный запрос для предела будет затем:

SELECT @rownum:[email protected] + 1 AS myRowSerial, 
* 
FROM myTable, (SELECT @rownum:=10) AS nothingButSetInitialValue 
LIMIT 10,10 

Тогда для следующего набора записей, было бы:

SELECT @rownum:[email protected] + 1 AS myRowSerial, 
* 
FROM myTable, (SELECT @rownum:=20) AS nothingButSetInitialValue 
LIMIT 20,10 

Еще раз спасибо, это действительно спас мой день !! :)

** UPDATE: ** Это НЕ будет работать, если у вас есть предложение GROUP BY в вашем запросе.

Смежные вопросы