2011-06-21 4 views
8
SELECT * FROM ScoresTable WHERE Score = 
    (SELECT MAX(Score) FROM ScoresTable AS st WHERE st.Date = ScoresTable.Date) 

Есть ли имя для описания с использованием инструкции SELECT в предложении WHERE? Это хорошая/плохая практика?Использование инструкции SELECT в предложении WHERE

Будет ли это лучшей альтернативой?

SELECT ScoresTable.* 
FROM ScoresTable INNER JOIN 
    (SELECT Date, MAX(Score) AS MaxScore 
    FROM ScoresTable GROUP BY Date) SubQuery 
    ON ScoresTable.Date = SubQuery.Date 
    AND ScoresTable.Score = SubQuery.MaxScore 

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

N.B. Мне нужно больше, чем просто дата и оценка (например, имя)

+0

Посмотрите на функции оконной обработки http://www.sqlbooks.ru/readarticle.aspx?part=02&file=sql200523 –

+0

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

+0

Действительно, они не требуются для этого простого примера, но они предлагают элегантные решения для более сложных вариантов этих типов запросов, поэтому их стоит знать. –

ответ

6

Это называется коррелированным подзапросом. У него есть его использование.

+0

Спасибо @Mladen. На ваш взгляд, это лучшее/наиболее эффективное решение проблемы? – jofitz

+3

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

7

Это совсем не плохая практика. Они обычно упоминаются как SUBQUERY, SUBSELECT или НЕИСПРАВНОЙ ЗАПРОС.

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

+0

Он также называется вложенным запросом? –

+1

@Gunner: да. Также подселек. –

+0

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

0

Подзапрос - это имя.

Время от времени требуется, но хорошее/плохое зависит от того, как оно применяется.

2

Принцип подзапросов совсем не плох, но я не думаю, что вы должны использовать его в своем примере. Если я правильно понимаю, вы хотите получить максимальный балл за каждую дату. В этом случае вы должны использовать GROUP BY.

+0

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

+0

Вы правы. К счастью, в MySQL (хотя я не уверен, что он это использует), он сможет выбирать столбцы, которые не агрегированы или в разделе group by. –

+0

Вы совершенно правы, @WinstonSmith, мне нужно получить имя, связанное с оценками, поэтому простой GROUP BY недостаточно. К сожалению, я не использую MySQL по этому поводу, @Lex; Мне стыдно говорить, что я использую Access :) – jofitz

1

Это коррелированный подзапрос.

(это «вложенный» запрос - это очень не-технический термин, хотя)

Внутренний запрос принимает значение от внешнего-запроса (WHERE st.Date = ScoresTable.Date), таким образом, оценивается один раз для каждой строки во внешнем запросе.

Существует также некоррелированная форма, в которой внутренний запрос независим, поскольку он выполняется только один раз.

например.

SELECT * FROM ScoresTable WHERE Score = 
    (SELECT MAX(Score) FROM Scores) 

Там нет ничего плохого в использовании подзапросов, кроме случаев, когда они не нужны :)

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

SELECT Max(score), Date FROM ScoresTable 
Group By Date 
+0

Функция агрегирования не будет работать, если вам нужно больше, чем пары MAX (Score) и Date. –

+0

Вы предполагаете, что ему нужно больше - лучше использовать только код для удовлетворения требований, а не для введения ненужной сложности. – BonyT

+0

Я не предполагаю - это очевидно из запроса, который начинается с 'SELECT *'. Конечно, это может быть просто ленивость, но это тоже будет предположение! –

3

Там гораздо лучший способ достичь желаемого результата с помощью SQL-сервера analytic (or windowing) functions.

SELECT DISTINCT Date, MAX(Score) OVER(PARTITION BY Date) FROM ScoresTable 

Если вам нужно больше, чем просто комбинации даты и макс балл, вы можете использовать функции ранжирования, например:

SELECT * 
FROM ScoresTable t 
JOIN ( 
    SELECT 
     ScoreId, 
     ROW_NUMBER() OVER (PARTITION BY Date ORDER BY Score DESC) AS [Rank] 
     FROM ScoresTable 
) window ON window.ScoreId = p.ScoreId AND window.[Rank] = 1 

Вы можете использовать RANK() вместо ROW_NUMBER() если вы хотите использовать несколько записей в возвращаются, если оба они имеют один и тот же MAX (Score).

+0

Любые функции окна ... –

+0

Спасибо @WinstonSmith, но ваше предложение кажется более сложным, чем необходимо. Это предлагает больше, чем мои первоначальные предложения? – jofitz

+0

В любом случае он не будет работать при доступе, но это то, что нужно иметь в виду, если вы перейдете на SQL-сервер в какой-то момент. –

1

В вашем случае сценарий, почему бы не использовать предложение GROUP BY и HAVING вместо таблицы JOINING для себя. Вы также можете использовать другую полезную функцию. see this link

+0

GROUP BY и HAVING не будут работать в этом случае, потому что, как указано в исходном вопросе: «Мне нужно больше, чем просто дата и оценка (например, имя)». Если вы снова проверите, вы обнаружите, что псевдонимы уже используются в вопросе. – jofitz

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