Ошибки Sql server? Результат запроса не является детерминированным, когда group BY expression?
у меня есть следующий запрос
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
результат (счет) изменить в любое время, когда он выполняется. И это намного меньше, чем должно быть. Я нашел один из следующих шагов может сделать это правильно.
- материализовать (temp или постоянная таблица) CTE
cte1
и вместо этого используйте материализованную таблицу. - изменить группу в
cte1
to любой следующих форм.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
в других CTEs. (обновление: этот шаг не всегда работает. Все еще есть проблема, когда она находится в табличной функции, хотя она работает, если запустить 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, -@param, getdate())
group by isnull(g.AAA, 'Unknown'), isnull(nullif(m1.value, 'NULL'), 'Unknown'), m.CCC
3 ответов
Я согласен, что это ошибка, так как у нее все еще есть проблема после опрошенного CTE, который использует select top ... order by ...
удалены.
SQL-это язык на основе. В этой парадигме порядок возвращаемых строк обычно не имеет значения. Вы можете думать о неупорядоченном как о поведении по умолчанию. Когда вы действительно хотите, чтобы строки были упорядочены, вам нужно явно использовать ORDER BY где-то в вашем запросе, чтобы указать, как заказать.
для обычных неупорядоченных запросов фактический порядок строк, возвращаемых запросом, может быть определен многими вещами. Например, физическое расположение строк на диске, порядок узлов индекса для индексов фактически используется оптимизатором запросов для возврата строк, фактического порядка выполнения шагов плана запроса и т. д.-Большинство из которых решаются во время выполнения и могут даже варьироваться между последующими исполнениями.
Если это то, что вы наблюдаете, это не ошибка, а принципиальное и нормальное поведение во всех реляционных СУБД.
Это можно сделать, как показано ниже кода:
AND ISNULL(<column name>,'''') LIKE ' +
CASE WHEN @customer IS NOT NULL
THEN '''' +@customer + ''''
ELSE
'ISNULL(c.<column_name> , '''')'
END