01.if object_id ( N'dbo.test_table',
N'U' )
is
not null02. drop
table
dbo.test_table;03.go04. 05.create
table
dbo.test_table ( id int
identity06. ,
a int07. ,
b int08. ,
c int09. ,
d int10. ,
e int11. );12.go13. 14.insert
into
dbo.test_table15.select
10, 5, 12, 56, 216.union
all17.select
100, 45, 78, 6, 12218.union
all19.select
150, 50, 127, 596, 2220.union
all21.select
3410, 55, 0, -45, 9022.union
all23.select
-10, -5, 0, -56, -2;20.union
all21.select
3410, 55, 0, -45, 9022.union
24.gomax 01.png
А теперь несколько примеров, как найти максимум в каждой строке по всем колонкам.
1. Выражение CASE (любая версия)
01.select
*02. , max_val =
case
when ( a >= b ) and
( a >= c ) and
( a >= d ) and
( a >= e )03. then
a04. when
( b >= a ) and
( b >= c ) and
( b >= d ) and
( b >= e )05. then
b06. when
( c >= a ) and
( c >= b ) and
( c >= d ) and
( c >= e )07. then
c08. when
( d >= a ) and
( d >= b ) and
( d >= c ) and
( d >= e )09. then
d10. else
e11. end12. from
dbo.test_table2. Подзапрос и оператор UNION (любая версия)
01.select
*02. , max_val =
( select
max(i) 03. from
( select
a 04. union
all05. select
b 06. union
all07. select
c08. union
all09. select
d10. union
all11. select
e12. )
t(i)13. )14. from
dbo.test_table3. Подзапрос и предложение VALUES (SQL Server 2008 и выше)
01.select
*02. , max_val =
( select
max(i) 03. from
( values
(a)04. ,(b)05. ,(c)06. ,(d)07. ,(e)
08. &nbcode> ,(d)07. ,(e)
)
t(i)09. )10. from
dbo.test_table4. Оператор UNPIVOT (SQL Server 2005 и выше)
1.select
id, max(val)
as
max_val2. from
( select
* 3. from
dbo.test_table t4. unpivot
( val for
col in ( [a],[b],[c],[d],[e]) ) up5. 6. ) t7. group
by
id5. Оператор UNPIVOT и ранжирующие функции (SQL Server 2005 и выше)
1.select
top
1 with
ties id, val 2. from
dbo.test_table t3. unpivot ( val
for
col in ( [a],[b],[c],[d],[e]) ) up4. order
by
row_number() over ( partition by
id order
by
val desc
)6. Оператор CROSS APPLY (SQL Server 2005 и выше)
01.select
* 02. from
dbo.test_table t03. cross
apply ( select
top
1 val 04. from
( values
(a),(b),(c),(d),(e) ) t (val)05. order
by
val desc06. )
ca (max_val)07. 08.--Ещё вариант09. desc
06. )
ca (max_val)07. 08.--Ещё вариант10.select
id, a, b, c, d, e, max_val11. from
dbo.test_table t12. cross
apply ( select
row_number() over (order
by
val desc) i, val13. from
( values
(a),(b),(c),(d),(e) ) t (val)14. )
ca (i, max_val)15. where
ca.i = 17. Inline-функция и CTE (SQL Server 2005 и выше)
01.if object_id ( N'dbo.f_get_max',
N'IF' )
is
not null02. drop
function
dbo.f_get_max;03.go04.create
function
dbo.f_get_max ( 05. @a
int06. , @b
int07. , @c
int08. , @d
int09. , @e
int10.)
returns
table11.as12.return13.with
cte14.as11.as12.return13.with
cte14.as(
select
val from16. (
values
(@a),(@b),(@c),(@d),(@e) 17. ) t(val)18.)19.select
max(val)
as
max_val from
cte;20.go
21. 22.select
* from
dbo.test_table t23. cross
apply dbo.f_get_max ( a, b, c, d, e )24.goА теперь посмотрим на производительность этих запросов, чтобы определить, какой из вариантов более предпочтителен. Тест буду проводить также на 5 колонках таблицы с 10 млн. записей.
001.set
nocount on;002.go003. 004.if object_id ( N'dbo.test_table',
N'U' )
is
not null005. drop
table
dbo.test_table;006.go007. 008.create
table
dbo.test_table ( id int
identity primary
key
clustered009. ,
a int010. ,
b int011. ,
c int012. ,
d int013. ,
e int014. );015.go016. ,
e int014. );015.go017.--Генерим 10 млн строк018.with
cte 019.as020.(
021. select
1 i022. union
all023. select
i+1 from
cte where
i < 10000000024.)025.insert
into
dbo.test_table026.select
checksum ( newid() ) % 1000 as
a027. , checksum
( newid() ) % 1000 as
b028. , checksum
( newid() ) % 1000 as
c029. , checksum
( newid() ) % 1000 as
d030. , checksum
( newid() ) % 1000 as
e031. from
cte032.option
( maxrecursion 0 );033. 034.declare
@val int;035. 036.print
'1. Выражение CASE (любая версия)';037.set
statistics
time on;038. 039.select
@val = case
when
( a >= b ) and
( a >= c ) and
( a >= d ) and
( a >= e )040. then
a041. when
( b >= a ) and
( b >= c ) and
( b >= d ) and
( b >= e )042. then
b043. when
( c >= a ) and
( c >= b ) and
( c >= d ) and
( c >= e )044. then
c045. when
( d >= a ) and
( d >= b ) and
( d >= c ) and
( d >= e )046. then
d047. else
e048. end049. from
dbo.test_table;050. 051.set
statistics
time off;052. 053.print
'2. Подзапрос и оператор UNION (любая версия)';054.set
statistics
time on;055. 056.select
@val = ( select
max(i)
057. from
( select
a 058. union
all059. select
b 060. union
all061. select
c062. union
all063. select
d064. union
all065. select
e066. )
t(i)067. )068. from
dbo.test_table;069. 070.set
statistics
time off;071. 072.print
'3. Подзапрос и предложение VALUES (SQL Server 2008 и выше)';073.set
statistics
time on;074. 075.select
@val = ( select
max(i)
076. from
( values
(a)077. ,(b)078. ,(c)079. ,(d)080. ,(e)
081. )
t(i)082. )083. from
dbo.test_table;084. 085.set
statistics
time off;086. 087.print
'4. Оператор UNPIVOT (SQL Server 2005 и выше)';088.set
statistics
time on;089. 090.select
@val = max(val)091. from
( select
* 092. from
dbo.test_table t093. unpivot
( val for
col in ( [a],[b],[c],[d],[e]) ) up094. 095. ) t096. group
by
id;097. 098.set
statistics
time off;099. 100.print
'5. Оператор UNPIVOT и ранжирующие функции (SQL Server 2005 и выше)';101.set
statistics
time on;102. 103.select
top
1 with
ties @val = val 104. from
dbo.test_table t105. unpivot ( val
for
col in ( [a],[b],[c],[d],[e]) ) uptop
1 with
ties @val = val 104. &nbsround-color:#f8f8f8;">106. order
by
row_number() over ( partition by
id order
by
val desc
);107. 108.set
statistics
time off;109. 110.print
'6. Оператор CROSS APPLY (SQL Server 2005 и выше)';111. 112.print
'CROSS APPLY 1';113.set
statistics
time on;114.select
@val = max_val 115. from
dbo.test_table t116. cross
apply ( select
top
1 val 117. from
( values
(a),(b),(c),(d),(e) ) t (val)118. order
by
val desc119. )
ca (max_val);120. 121.print
'CROSS APPLY 2';122.select
@val = max_val123. from
dbo.test_table t124. cross
apply ( select
row_number() over (122.order
by
val desc) i, val125. from
( values
(a),(b),(c),(d),(e) ) t (val)126. )
ca (i, max_val)127. where
ca.i = 1;128. 129.set
statistics
time off;130. 131.print
'7. Inline-функция и CTE (SQL Server 2005 и выше)';132.set
statistics
time on;133. 134.select
@val = max_val from
dbo.test_table t 135. cross
apply dbo.f_get_max ( a, b, c, d, e );136. 137.set
statistics
time off;138.goРезультат ниже:
01.1. Выражение
CASE (любая версия)02. 03.SQL Server Execution Times:04. CPU
time
= 3416 ms, elapsed time
= 3416 ms.05.----------------------------------------------------------------------06. 07.2. Подзапрос и оператор
UNION
(любая версия)08. 09.SQL Server Execution Times:10. CPU
time
= 12777 ms, elapsed time
= 3848 ms.11.----------------------------------------------------------------------12. 13.3. Подзапрос и предложение
VALUES
(SQL Server 2008 и выше)14. 15.SQL Server Execution Times:16. CPU
time
= 13182 ms, elapsed 3. Подзапрос и предложение
VALUES
(SQL Server 2008 и выше)14. 15.time
= 3968 ms.17.----------------------------------------------------------------------18. 19.4. Оператор UNPIVOT (SQL Server 2005
и выше)20. 21.SQL Server Execution Times:22. CPU
time
= 22246 ms, elapsed time
= 15966 ms.23.----------------------------------------------------------------------24. 25.5. Оператор UNPIVOT и ранжирующие функции
(SQL Server 2005 и выше)26. 27.SQL Server Execution Times:28. CPU
time
= 153957 ms, elapsed time
= 239071 ms.29.----------------------------------------------------------------------30. 31.6. Оператор
CROSS APPLY (SQL Server 2005 и выше)32. 33.CROSS
APPLY 134. 35.SQL Server Execution Times:36. CPU
time
= 22963 ms, elapsed time
= 6273 ms.37. 38.CROSS
APPLY 239. 40.SQL Server Execution Times:41. CPU
time
= 33244 ms, elapsed time38.CROSS
APPLY 2
= 9270 ms.42.----------------------------------------------------------------------43. 44.7. Inline-функция и CTE (SQL Server
2005 и выше)45. 46.SQL Server Execution Times:47. CPU
time
= 12246 ms, elapsed time
= 3787 ms.