Вычисление количества (*) уникальных вхождений в новый столбец без группировки в одном запросе выбора

Возможно ли в 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 в каждой строке, хотя это и есть желаемый результат:

имя1 имя2 имя3 имя4 ShowCountOfName3PerName1&Name2OnEveryRow t1_1 т2_1 т3_1 т4_3 1 t1_1 т2_2 т3_1 т4_8 3 t1_1 т2_2 т3_3 т4_6 3 t1_1 т2_2 т3_4 т4_9 3 t1_1 т2_3 т3_1 т4_7 1 т1_2 т2_1 т3_4 т4_1 1 т1_2 т2_2 т3_2 т4_4 2 т1_2 т2_2 т3_3 t4_10 2

Я попробовал это так:

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. Любые подсказки будут приняты с благодарностью!

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

Dale K 04.07.2024 08:13

ОК, я отредактирую. Я действительно сожалею!

user2177283 04.07.2024 08:15

Я думаю, что вам нужен подсчет окон, ознакомьтесь с документацией over (partition by)

Dale K 04.07.2024 08:15

GROUP BY означает, что ваш подзапрос тоже не нужен; это бесполезно или может вызвать ошибку.

Thom A 04.07.2024 08:28

Вы показали нам свой нерабочий результат, но вам нужно показать нам те результаты, которых вы желаете достичь.

Dale K 04.07.2024 10:00

@Дейл К, ты прав. Я просто отредактировал вопрос, чтобы показать, что мне нужно получить в результате запроса.

user2177283 04.07.2024 16:16
ReactJs | Supabase | Добавление данных в базу данных
ReactJs | Supabase | Добавление данных в базу данных
Это и есть ваш редактор таблиц в supabase.👇
Понимание Python и переход к SQL
Понимание Python и переход к SQL
Перед нами лабораторная работа по BloodOath:
2
6
82
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Ваша ошибка — использование 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

Другие вопросы по теме