Возможно ли в SQL Server сделать что-то похожее на этот упрощенный пример одним выбором? Гугляя сам, я наткнулся на вопрос по SO с очень похожим требованием, но, к сожалению, он не связан с SQL Server.
declare @t1 table (id int, name varchar(60))
declare @t2 table (id int, name varchar(60))
declare @t3 table (id int, name varchar(60))
declare @t4 table (t1id int, t2id int, t3id int, id int, name varchar(60))
insert into @t1 values
(1, 't1_1'),
(2, 't1_2')
insert into @t2 values
(1, 't2_1'),
(2, 't2_2'),
(3, 't2_3')
insert into @t3 values
(1, 't3_1'),
(2, 't3_2'),
(3, 't3_3'),
(4, 't3_4')
insert into @t4 values
(2, 1, 4, 1, 't4_1'),
(3, 2, 1, 2, 't4_2'),
(1, 1, 1, 3, 't4_3'),
(2, 2, 2, 4, 't4_4'),
(3, 3, 3, 5, 't4_5'),
(1, 2, 3, 6, 't4_6'),
(1, 3, 1, 7, 't4_7'),
(1, 2, 1, 8, 't4_8'),
(1, 2, 4, 9, 't4_9'),
(2, 2, 3, 10, 't4_10')
select base.*,
( -- https://learn.microsoft.com/en-us/sql/t-sql/queries/table-value-constructor-transact-sql?view=sql-server-ver16#c-specifying-multiple-values-as-a-derived-table-in-a-from-clause
select count(distinct v.name3)
from
(
values (base.name1, base.name2, base.name3)
) as v (name1, name2, name3)
group by v.name1, v.name2
) as [ShowCountOfName3PerName1&Name2OnEveryRow]
from
(
select t1.name as name1,
t2.name as name2,
t3.name as name3,
t4.name as name4
from @t4 as t4
inner join @t1 as t1
on t4.t1id = t1.id
inner join @t2 as t2
on t4.t2id = t2.id
inner join @t3 as t3
on t4.t3id = t3.id
) as base
order by base.name1, base.name2, base.name3, base.name4
К сожалению, этот запрос отображает только цифру 1 в каждой строке, хотя это и есть желаемый результат:
Я попробовал это так:
select base.*,
cnt.[ShowCountOfName3PerName1&Name2OnEveryRow]
from
(
select t1.name as name1,
t2.name as name2,
t3.name as name3,
t4.name as name4
from @t4 as t4
inner join @t1 as t1
on t4.t1id = t1.id
inner join @t2 as t2
on t4.t2id = t2.id
inner join @t3 as t3
on t4.t3id = t3.id
) as base
outer apply
(
select base.name1, base.name2,
count(distinct base.name3) as [ShowCountOfName3PerName1&Name2OnEveryRow]
from base
group by base.name1, base.name2
) as cnt
where base.name1 = cnt.name1
and base.name2 = cnt.name2
order by base.name1, base.name2, base.name3, base.name4
Результатом является недопустимое имя объекта «база». Я могу представить это как хранимую процедуру, в которую я вставляю результат в объявленную таблицу @result(...), а затем обновляю набор @result..., но в этом случае это должна быть хранимая процедура и перечислять набор результатов. из более чем 100 тыс. строк и каждый раз обновлять их все. Хотя мне нужно, чтобы это было представление, чтобы иметь возможность более эффективно запрашивать его с помощью Entity Framework. Любые подсказки будут приняты с благодарностью!
ОК, я отредактирую. Я действительно сожалею!
Я думаю, что вам нужен подсчет окон, ознакомьтесь с документацией over (partition by)
GROUP BY
означает, что ваш подзапрос тоже не нужен; это бесполезно или может вызвать ошибку.
Вы показали нам свой нерабочий результат, но вам нужно показать нам те результаты, которых вы желаете достичь.
@Дейл К, ты прав. Я просто отредактировал вопрос, чтобы показать, что мне нужно получить в результате запроса.
Ваша ошибка — использование APPLY
join в обоих случаях. Он будет принимать значения только для текущей строки, поэтому вы всегда получите 1.
Решение 1. Используйте оконную функцию
Есть одна загвоздка: COUNT( DISTINCT x ) OVER
не поддерживается в SQL Server.
Вместо этого можно использовать обходной путь DENSE_RANK()
:
SELECT *, DENSE_RANK() OVER( PARTITION BY t1id, t2id ORDER BY t3id ASC ) + DENSE_RANK() OVER( PARTITION BY t1id, t2id ORDER BY t3id DESC ) - 1
FROM @T4
Решение 2. Используйте простой INNER JOIN
SELECT Src.*, Cnt.Cnt
FROM @T4 AS Src
INNER JOIN(
SELECT t1id, t2id, COUNT( DISTINCT t3id ) AS Cnt
FROM @T4
GROUP BY t1id, t2id
) AS Cnt
ON Src.t1id = Cnt.t1id AND Src.t2id = Cnt.t2id
P.S. для краткости я не включил объединения с таблицами t1, t2, t3
В соответствии с руководством по вопросам не публикуйте изображения кода, данных, сообщений об ошибках и т. д. — скопируйте или введите текст в вопрос. Пожалуйста, ограничьте использование изображений для диаграмм или демонстрации ошибок рендеринга, вещей, которые невозможно точно описать с помощью текста.