Ответ 1
Я согласен с этим, так как он все еще имеет проблему после удаления запрошенного CTE, который использует select top ... order by ...
.
У меня есть следующий запрос
with cte1 as (
select isnull(A, 'Unknown') as A,
isnull(nullif(B, 'NULL'), 'Unknown') as B,
C
from ... -- uses collate SQL_Latin1_General_CP1_CI_AS when joining
group by isnull(A, 'Unknown'), isnull(nullif(B, 'NULL'), 'Unknown'), C
),
cte2 as (select top (2147483647) A, B, C from cte1 order by A, B, C),
-- Removing cte2 makes it work if running directly as SQL query. However,
-- it still behave the same if the code is in view or table function
ctes as (
.... -- pretty complex query joining cte2 multiple times
-- uses row_number(), ntile
)
select count(*) from finalCTE
Результат (количество) изменяется каждый раз при его выполнении. И это намного меньше, чем должно быть. Я нашел, что любой из следующих шагов может сделать это правильно.
cte1
и используйте вместо этого материализованную таблицу.cte1
на любую следующих форм.
group by A, isnull(nullif(B, 'NULL'), 'Unknown'), C
group by isnull(A, 'Unknown'), nullif(B, 'NULL'), C
group by A, nullif(B, 'NULL'), C
cte1
вместо cte2
в других CTE. ( Обновление: Этот шаг не всегда работает. Тем не менее проблема связана с функцией таблицы, хотя она работает, если вы запускаете SQL напрямую)Однако, почему исходный запрос ведет себя странно? Это ошибка в SQL Server?
Полный функциональный код:
ALTER function [dbo].[fn] (@para1 char(3))
returns table
return
with cte1 as ( select AAA, BBB, CCC
from dbo.fnBBB(12)
where @para1 = 'xxxx'
union all
select AAA, BBB, CCC
from dbo.fnBBB2(12)
where @para1 = 'yyyy'
),
-- Tested not using cte2, the same behave
cte2 as (select top (2147483647) AAA, BBB, CCC from cte1 order by AAA, BBB, CCC),
t as ( select e.CCC, e.value1, cte2.BBB, cte2.AAA
from dbo.T1 e
join cte2 on e.CCC = cte2.CCC
),
b as ( select BBB, AAA, count(*) count,
case when count(*) / 5 > 10 then 10
else count(*) / 5
end as buckets
from t
group by BBB, AAA
having count(*) >= 5
),
b2
as ( select t.*
from b
cross apply ( select *,
ntile(b.buckets) over ( partition by t.BBB, t.AAA order by value1, CCC )
as bucket
from t
where BBB = b.BBB
and AAA = b.AAA
) t
),
m1
as ( select AAA, BBB, b2.CCC, Date, SId, value2, b2.bucket, --
_asc = row_number() over ( partition by BBB, AAA, bucket, Date, SId order by value2, b2.CCC ),
_desc = row_number() over ( partition by BBB, AAA, bucket, Date, SId order by value2 desc, b2.CCC desc )
,count(*) over (partition by BBB, AAA, bucket, Date, SId) scount
from b2 join dbo.T2 e on b2.CCC = e.CCC
),
median
as ( select BBB, AAA, bucket, Date, SId, avg(value2) value2Median, min(scount) sCount
from m1
where _asc in ( _desc, _desc - 1, _desc + 1 )
group by BBB, AAA, bucket, Date, SId
),
bounds
as ( select BBB, AAA, bucket, min(value1) dboMin, max(value1) value1Max, count(*) count
from b2
group by BBB, AAA, bucket
)
select m.*, b.dboMin, b.value1Max, Count
from median m join bounds b on m.BBB = b.BBB and m.AAA = b.AAA and m.bucket = b.bucket
-- order by BBB, AAA, bucket
Функция, используемая в cte1:
CREATE function [dbo].[fnBBB](@param int)
returns table
return
with m as ( select * -- only this view has non default collate (..._CS_AS)
from dbo.view1 -- indxed view.
)
select isnull(g.AAA, 'Unknown') as AAA,
isnull(nullif(m1.value, 'NULL'), 'Unknown') as BBB
, m.CCC
from m
left join dbo.mapping m0 on m0.id = 12
and m0.value = m. v1 collate SQL_Latin1_General_CP1_CI_AS
left join dbo.map1 r on r.Country = m0.value
left join dbo.map2 g on g.N = r.N
left join dbo.mapping m1 on m1.id = 20
and m1.value = m.v2 collate SQL_Latin1_General_CP1_CI_AS
where m.run_date > dateadd(mm, [email protected], getdate())
group by isnull(g.AAA, 'Unknown'), isnull(nullif(m1.value, 'NULL'), 'Unknown'), m.CCC
Я согласен с этим, так как он все еще имеет проблему после удаления запрошенного CTE, который использует select top ... order by ...
.
SQL - это язык, основанный на наборе. В этой парадигме порядок возвращаемых строк обычно не имеет значения. Вы можете считать неупорядоченным как поведение по умолчанию. Когда вы действительно хотите упорядочить строки, вам нужно явно использовать ORDER BY где-нибудь в вашем запросе, чтобы указать порядок заказа.
Для обычных неупорядоченных запросов фактический порядок строк, возвращаемых запросом, может определяться многими вещами. Например, физическое расположение строк на диске, порядок узлов индекса для индексов, фактически используемых оптимизатором запросов для возврата строк, фактический порядок выполнения шагов плана запроса и т.д. - большинство из них решаются во время выполнения и могут даже варьироваться в зависимости от последующих исполнений.
Если это то, что вы наблюдаете, это не ошибка, а фундаментальное и нормальное поведение во всех реляционных СУБД.
Это можно сделать, как показано ниже:
AND ISNULL(<column name>,'''') LIKE ' +
CASE WHEN @customer IS NOT NULL
THEN '''' [email protected] + ''''
ELSE
'ISNULL(c.<column_name> , '''')'
END