2014-10-22 2 views
1

Есть ли способ иметь столбец из другой таблицы со значением, которое всегда совпадает внутри Вид> Примера:SQL Server столбец из другой таблицы со статическим Значением в поле зрения

SELECT *, 
    (SELECT value FROM tblStudentPrefixes WHERE PrefixName = 'SeniorPrefix') 
    AS StudentPrefix 
FROM tblStudents 

Будет выше вложенный запрос выполнить каждую строку? Есть ли способ выполнить его один раз и использовать для всех строк.

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

+0

если вы PrefixName уникален, вы можете переписать его как внешнее соединение –

ответ

4

Это на самом деле зависит от вашей таблицы, созданной. Если prefixName не может быть уникальным, вы можете столкнуться с ошибками, когда подзапрос возвращает более одной строки. Если он не ограничен уникальным, но, оказывается, уникален для SeniorPrefix, тогда ваш запрос будет выполнен 1000 раз. Для демонстрации я использовал следующий DDL:

CREATE TABLE #tblStudents (ID INT IDENTITY(1, 1), Filler CHAR(100)); 
INSERT #tblStudents (Filler) 
SELECT TOP 10000 NULL 
FROM sys.all_objects a, sys.all_objects b; 

CREATE TABLE #tblStudentPrefixes (Value VARCHAR(10), PrefixName VARCHAR(20)); 
INSERT #tblStudentPrefixes (Value, PrefixName) VALUES ('A Value', 'SeniorPrefix'); 

Запуск ваш запрос дает следующий вывод IO:

Table '#tblStudentPrefixes'. Scan count 10000, logical reads 10000

Table '#tblStudents'. Scan count 1, logical reads 142

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

Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.

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

SELECT *, 
    (SELECT TOP 1 value FROM #tblStudentPrefixes WHERE PrefixName = 'SeniorPrefix' ORDER BY Value) 
    AS StudentPrefix 
FROM #tblStudents 

НЛ теперь становится:

Table '#tblStudentPrefixes'. Scan count 1, logical reads 1

Table '#tblStudents'. Scan count 1, logical reads 142

Тем не менее, я бы до сих пор г ecommend переключение на CROSS JOIN здесь:

SELECT s.*, p.Value AS StudentPrefix 
FROM #tblStudents AS s 
     CROSS JOIN 
     ( SELECT TOP 1 value 
      FROM #tblStudentPrefixes 
      WHERE PrefixName = 'SeniorPrefix' 
      ORDER BY Value 
     ) AS p; 

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

enter image description here

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


EDIT

В свете того факта, что вам нужно возвращать строки из tblstudent, когда нет матча за SeniorPrefix в tblStudentPrefixes, и что PrefixName не CurrentY constrianed быть уникальным, то лучшим решение:

SELECT *, 
    (SELECT MAX(value) FROM #tblStudentPrefixes WHERE PrefixName = 'SeniorPrefix') 
    AS StudentPrefix 
FROM #tblStudents; 

Если ограничить его уникальным, то следующие 3 запросов производства (essentiall у) тот же план и те же результаты, это просто личные предпочтения:

SELECT *, 
    (SELECT value FROM #tblStudentPrefixes WHERE PrefixName = 'SeniorPrefix') 
    AS StudentPrefix 
FROM #tblStudents; 

SELECT s.*, p.Value AS StudentPrefix 
FROM #tblStudents AS s 
     LEFT JOIN #tblStudentPrefixes AS p 
      ON p.PrefixName = 'SeniorPrefix'; 

SELECT s.*, p.Value AS StudentPrefix 
FROM #tblStudents AS s 
     OUTER APPLY 
     ( SELECT Value 
      FROM #tblStudentPrefixes 
      WHERE PrefixName = 'SeniorPrefix' 
     ) AS p; 
+0

Спасибо. Я попробовал следующее, которое дало мне желаемые результаты, прежде чем проверять ответы на SO. Считаете ли вы, что ваш запрос будет иметь лучшую производительность? 'SELECT s. *, P.Value AS StudentPrefix FROM tblStudents s LEFT JOIN tblStudentPrefixes ON p.PrefixName = 'SeniorPrefix'' – user3656029

+0

Это зависит, но я сомневаюсь. С 'LEFT JOIN', если он ограничен уникальным, у вас есть такая же ленивая проблема катушки, описанная выше, с подвыборкой, и если она не ограничена уникальной, у вас есть такая же проблема с объединением вложенного цикла и получением 1000 просмотров tblStudentPrefixes. – GarethD

+0

Я полагаю, что ключевой вопрос: всегда будет значение для 'SeniorPrefix' в tblStudentPrefixes? Вы хотите вернуть результаты, если их нет? – GarethD

0

Все в порядке. Подзапрос будет выполняться для каждой строки в каждой строке (что может обеспечить плохую производительность). Вы можете попробовать также:

SELECT tblStudents.*,StudentPrefix.value 
    FROM tblStudents, 
     (SELECT value 
     FROM tblStudentPrefixes 
     WHERE PrefixName = 'SeniorPrefix')StudentPrefix 
1

Я надеюсь, что я понимаю ваш вопрос правильно, но попробовать это

SELECT * 
FROM tblStudents 
Outer Apply 
    (
    SELECT value 
    FROM tblStudentPrefixes 
    WHERE PrefixName = 'SeniorPrefix' 
    ) as tble 
Смежные вопросы