#sql #sql-server #join #subquery
#sql #sql-сервер #Присоединиться #подзапрос
Вопрос:
Мой запрос на SQL Server:
select
s.learners_id, s.cv_student_id,
s.first_name ' ' s.last_name student_name,
p.program_name, dc.fulldate program_start_date,
sd.discount_value, dt.type_name
from
fact_student_programs_t sp
left join
object_sTATUSES_T os on os.object_statusid = sp.status_id
inner join
dim_programs_t p on p.programs_sk_id = sp.programs_sk_id
left join
dim_calendar dc on dc.datekey = sp.start_date_key
inner join
dim_students_t s on s.students_sk_id = sp.students_sk_id
outer join
(select
s.learners_id, sd.discount_value, dt.type_name
from
fact_student_discountS_T sd
inner join
discount_types_t dt on dt.id = sd.discount_type_id
inner join
dim_students_t s on s.students_sk_id = sd.students_sk_id
where
sd.curr_in = 1) discounts on discounts.learners_id = s.learners_id
where
sp.curr_in = 1
and dc.fulldate is not null
and os.status_name in ('Active')
and s.learners_id in ('201328', '237744', '237817', '239826', '308486', '308961',
'308973', '309352', '311521', '312269', '312951',
'313254', '313289', '384170', '384224', '384228',
'408911', '408912', '408936', '411293', '411308',
'411322', '411324', '411325', '411352', '411413',
'411417', '412865', '412923')
Я пытаюсь объединить эти два запроса, и у меня возникают проблемы. Является ли оператор внешнего соединения неправильным? Может кто-нибудь, пожалуйста, помочь мне исправить этот код?
РЕДАКТИРОВАТЬ: внешнее соединение здесь недопустимый синтаксис, поэтому я использую левое соединение. Запрос по-прежнему возвращает ошибку:
Msg 4104, Level 16, State 1. The multi-part identifier "dt.type_name" could not be bound. Msg 4104, Level 16, State 1. The multi-part identifier "sd.discount_value" could not be bound. (Line 2)
Комментарии:
1. Пожалуйста, ознакомьтесь с допустимым синтаксисом SQL Server и визуальным представлением данных, которые он возвращает здесь: sqlservertutorial.net/sql-server-basics/sql-server-joins
Ответ №1:
Краткие сведения
outer join
я полагаю, что недопустимо в SQL Server / t-sql. Это должно быть либо left outer join
, right outer join
либо full outer join
.
В вашей ситуации, я подозреваю, вы хотите, чтобы это было left outer join
.
Объяснение / более длинная версия
В левом и правом внешних соединениях «левый» и «правый» относятся к таблицам / etc буквально слева и справа от соединения (например, до и после объединения, соответственно).
- В левом внешнем соединении он принимает все значения из таблицы слева (первая таблица) и любые совпадающие строки в таблице справа
- При правильном внешнем соединении он принимает все значения из таблицы справа (вторая таблица) и любые совпадающие строки в таблице слева
Полное внешнее соединение получает все строки из обеих таблиц и сопоставляет их, когда это возможно.
Вот пример
/* Data setup */
CREATE TABLE #T1 (T1_ID int);
CREATE TABLE #T2 (T2_ID int);
INSERT INTO #T1 (T1_ID) VALUES (1), (2);
INSERT INTO #T2 (T2_ID) VALUES (1), (3);
/* Example joins */
SELECT #T1.T1_ID, #T2.T2_ID
FROM #T1
LEFT OUTER JOIN #T2 ON #T1.T1_ID = #T2.T2_ID;
SELECT #T1.T1_ID, #T2.T2_ID
FROM #T1
RIGHT OUTER JOIN #T2 ON #T1.T1_ID = #T2.T2_ID;
SELECT #T1.T1_ID, #T2.T2_ID
FROM #T1
FULL OUTER JOIN #T2 ON #T1.T1_ID = #T2.T2_ID;
/* Results
-- LEFT OUTER JOIN
T1_ID T2_ID
1 1
2 NULL
-- RIGHT OUTER JOIN
T1_ID T2_ID
1 1
NULL 3
-- FULL OUTER JOIN
T1_ID T2_ID
1 1
2 NULL
NULL 3
*/
Учитывая, что у вас есть WHERE s.learners_id in (...)
в вашем предложении WHERE, это означает, что вам не нужны строки, в которых s.learners будет NULL .
- Если у вас было правильное внешнее соединение, то требование WHERE эффективно превратит правильное внешнее соединение во внутреннее соединение (поскольку оно исключит все строки, где s.learners_id равно NULL).
- Если бы у вас было полное внешнее соединение, то требование WHERE эффективно превратило бы полное внешнее соединение в левое внешнее соединение — по аналогичным логическим линиям.
Комментарии:
1. Спасибо за ответ. Да, левое соединение — это то, что мне нужно. Этот код не выполняется. Мое сообщение об ошибке:
Msg 4104, Level 16, State 1. The multi-part identifier "dt.type_name" could not be bound. Msg 4104, Level 16, State 1. The multi-part identifier "sd.discount_value" could not be bound. (Line 2)
2. Поскольку таблица с псевдонимом sd является частью подзапроса, внешний запрос не может видеть саму таблицу; внешний запрос может использовать только подзапрос с псевдонимом as
discounts
. Попробуйте использоватьdiscounts.type_name
anddiscounts.discount_value
во внешнем select .