Я прочитал в техническом описании настройки Microsoft T-SQL , что коррелированные подзапросы могут быть дорогостоящими с точки зрения производительности для большой таблицы:
... Сравнитьэто первое решение, которое будет сканировать всю таблицу и выполнять коррелированный подзапрос для каждой строки.Разница в производительности незначительна на маленьком столе.Но для большой таблицы это может составлять часы обработки ...
Существует ли общий способ преобразования запроса с несколькими агрегациями, основанными на разных критериях, в виде коррелированных подзапросов в один запрос?который использует JOIN
s вместо коррелированных подзапросов?
Рассмотрим пример:
Подготовьте схему:
CREATE TABLE Student (
ID INT NOT NULL PRIMARY KEY IDENTITY(1,1),
Name NVARCHAR(255) NOT NULL
);
CREATE TABLE Grade (
ID INT NOT NULL PRIMARY KEY IDENTITY(1,1),
StudentID INT NOT NULL FOREIGN KEY REFERENCES Student(ID),
Score INT NOT NULL,
CONSTRAINT CK_Grade_Score CHECK (Score >= 0 AND Score <= 100)
);
INSERT INTO Student (Name) VALUES ('Steven');
INSERT INTO Student (Name) VALUES ('Timmy');
INSERT INTO Student (Name) VALUES ('Maria');
INSERT INTO Grade (StudentID, Score) VALUES (1, 90);
INSERT INTO Grade (StudentID, Score) VALUES (1, 81);
INSERT INTO Grade (StudentID, Score) VALUES (1, 82);
INSERT INTO Grade (StudentID, Score) VALUES (1, 82);
INSERT INTO Grade (StudentID, Score) VALUES (2, 99);
INSERT INTO Grade (StudentID, Score) VALUES (2, 63);
INSERT INTO Grade (StudentID, Score) VALUES (2, 97);
INSERT INTO Grade (StudentID, Score) VALUES (2, 90);
INSERT INTO Grade (StudentID, Score) VALUES (3, 66);
INSERT INTO Grade (StudentID, Score) VALUES (3, 61);
INSERT INTO Grade (StudentID, Score) VALUES (3, 60);
Вопрос в вопросе:
SELECT Name,
(SELECT AVG(Score) FROM Grade WHERE StudentID = Student.ID AND Score < 65) AS 'F',
(SELECT AVG(Score) FROM Grade WHERE StudentID = Student.ID AND Score >= 65 AND Score < 70) AS 'D',
(SELECT AVG(Score) FROM Grade WHERE StudentID = Student.ID AND Score >= 70 AND Score < 80) AS 'C',
(SELECT AVG(Score) FROM Grade WHERE StudentID = Student.ID AND Score >= 80 AND Score < 90) AS 'B',
(SELECT AVG(Score) FROM Grade WHERE StudentID = Student.ID AND Score >= 90 AND Score <= 100) AS 'A'
FROM Student
Создает следующий результат:
Name F D C B A
-----------------------------------------
Steven NULL NULL NULL 81 90
Timmy 63 NULL NULL NULL 95
Maria 60 66 NULL NULL NULL
Мне известна техника, которую вы можете использовать с COUNT()
, где вы выполняете один SELECT
с JOIN
и затем используете оператор CASE
, чтобы дополнительно добавить 1 к счетчику, когда первичные ключи выстраиваются в линию между вашим соединением И ваше условие истинно.Я ищу подобную технику, которая может быть применена к различным типам агрегации (в отличие от просто COUNT
).
Существует ли эффективный способ преобразования этого примера запроса для использования JOIN
вместо нескольких подзапросов?