2009-11-25 3 views
2

У меня есть две таблицы, таблица фильмов (mt, основная таблица) и таблица, в которой доступны эти фильмы (st, вторичная таблица). Для каждой записи mt существует несколько st записей. Мне нужен запрос, который присоединится к записям и позволит мне запускать запросы на как на таблицы. Я в настоящее время использую внутреннее соединение, как это:SQL-логика: две таблицы (группа?)

SELECT * FROM 
(
    SELECT ROW_NUMBER() OVER(ORDER BY " + orderField + @") AS RowNum, 
      mt.ID AS mt_ID, 
      mt.title AS mt_title, 
      [...] 
      st.ID AS st_ID, 
      st.title AS st_title, 
      [...] 
    FROM mt AS mt 
    st AS st 
    INNER JOIN sttable AS st on mt.ID =st.ID 
    WHERE [email protected] <> 0 AND mt.title = @variable 
)  
    as DerivedTableName 
    WHERE RowNum between 
    ((@pageIndex - 1) * @pageSize + 1) and @pageIndex*@pageSize 

Проблема с этим состоит в том, что мне нужно, чтобы иметь возможность перебрать т с использованием RowNum и pageIndex, и запрос возвращает более одной записи для каждого фильма (например, , если есть 8 записей для определенного фильма, 8, а не 1, записи возвращаются). Я попытался использовать GROUP BY, но проблема в том, что он не позволит мне выполнять запросы по полям в подчиненной таблице (st).

Любая помощь относительно соответствующей логики была бы очень оценена.

+0

Не знаете, что вы пытаетесь достичь там. Запрос выполняется для возврата всех строк, которые имеют соответствующие mt и st. Вы хотите знать, сколько записей st для каждого mt? – MPelletier

ответ

1

Вот решение, которое делает GROUP BY в производной таблице подзапроса, так что вы получите только один строки на название фильма и вычислить ROW_NUMBER().

Затем снова присоедините результат производной таблицы к st во внешнем запросе. Там будет по-прежнему несколько строк на название фильма, но RowNum будет повторяться, чтобы вы могли правильно фильтровать ваш @pageIndex.

SELECT * FROM 
(
    SELECT ROW_NUMBER() OVER(ORDER BY " + orderField + @") AS RowNum, 
      mt.ID AS mt_ID, 
      mt.title AS mt_title, 
      [...] 
    FROM mt AS mt 
    INNER JOIN sttable AS st ON mt.ID =st.ID 
    WHERE mt.title = @variable 
    GROUP BY mt.ID 
) mt1 
INNER JOIN sttable AS st1 ON (mt1.ID = st1.ID) 
WHERE mt1.RowNum BETWEEN 
    ((@pageIndex - 1) * @pageSize + 1) AND @pageIndex*@pageSize; 

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

Если вы хотите сделать что-то вроде функции MySQL GROUP_CONCAT(), это сложно в Microsoft SQL Server (я полагаю, вы используете Microsoft).

См. Блоги, такие как http://blog.shlomoid.com/2008/11/emulating-mysqls-groupconcat-function.html, которые описывают использование трюка FOR xml PATH ('').

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


Re ваш комментарий: Я не думаю, что вам нужно сделать заказ на любой колонке st внутри подзапроса. Я предполагал, что не будет столбцов от st, включенных в список выбора подзапроса. Единственная причина, по которой есть экземпляр st, связанный в подзапросе, состоит в том, чтобы ограничить строки mt теми, у которых есть соответствующие строки в st. Но GROUP BY mt.ID гарантирует, что есть только одна строка в строке mt (фактически, поскольку это SQL Server, а не MySQL, вам нужно будет назвать все столбцы списка выбора в предложении GROUP BY).


Re ваш второй комментарий:

Я хочу первых дисплей мт строк, которые имеют соответствующие ул записи, которые были недавно добавлены

Вы можете добавить другие столбцы сгруппированных запрос, если вы используете функции группировки. Например, последние date_added на группу mt составляют MAX(st.date_added), и вы можете добавить этот столбец в подзапрос.

Однако в подзапросе не используйте ORDER BY. Там редко бывает какая-либо причина для сортировки подзапроса, так как порядок может быть изменена в любом случае, используя результат подзапроса в JOIN или другие операции, которые вы хотите использовать подзапрос в

Вы должны разобраться во внешнем запросе:.

SELECT * FROM 
(
    SELECT ROW_NUMBER() OVER(ORDER BY " + orderField + @") AS RowNum, 
      mt.ID AS mt_ID, 
      mt.title AS mt_title, 
      [...] -- other mt.* columns 
      MAX(st.date_added) AS latest_date_added 
    FROM mt AS mt 
    INNER JOIN sttable AS st ON mt.ID =st.ID 
    WHERE mt.title = @variable 
    GROUP BY mt.ID, -- other mt.* columns 
) mt1 
INNER JOIN sttable AS st1 ON (mt1.ID = st1.ID) 
WHERE mt1.RowNum BETWEEN 
    ((@pageIndex - 1) * @pageSize + 1) AND @pageIndex*@pageSize 
ORDER BY mt1.latest_date_added DESC, st1.date_added DESC; 
+0

Спасибо. Я теперь использую запрос, подобный тому, который вы предложили, но проблема, с которой я сталкиваюсь, заключается в том, что мне нужно иметь возможность сортировать st во внутреннем запросе, но когда я пытаюсь это сделать, мне говорят, что столбец I выбранные для сортировки, являются недопустимыми в списке выбора, потому что он не содержится ни в агрегатной функции, ни в предложении GROUP BY. Если я добавлю столбец в предложение GROUP BY, запрос снова запустит несколько строк для каждой записи mt. – alpheus

+0

OK - Да - у меня корректно работают столбцы mt (они находятся в списке выбора и в предложении GROUP BY), но как я могу сортировать по полю в st? Например, у меня есть поле в st, называемое «date_added», и я хочу заказать результаты mt по st.date_added (т. Е. Я хочу сначала отобразить строки mt, которые имеют соответствующие st-записи, которые были недавно добавлены). Я бы поместил код ORDER BY st.date_added во внешний запрос? – alpheus

+0

Thansk очень много. Я получил это, чтобы работать. – alpheus

0

Я не думаю, что вам нужно иметь как это:

FROM mt AS mt 
    st AS st 

и это:

INNER JOIN sttable AS st on mt.ID = st.ID 
+0

Не ответ, а действительное замечание. – MPelletier

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