Нужна помощь для улучшения запроса ниже (решение на основе Cte) - PullRequest
0 голосов
/ 16 июня 2011

Рассмотрим приведенную ниже таблицу ввода

Id  CountryName
1   India,Australia,Singapore,Pakistan,Bangaladesh
2   Norway,Argentina,Brazil,WestIndies,Burma

Желаемым выходом является

Id  Country1    Country2    Country3    Country4    Country5
1   India   Australia   Singapore   Pakistan    Bangalades
2   Norway  Argentina   Brazil  WestIndies  Burma

Я написал запрос, по которому нормально работает

;WITH cte AS (

SELECT 
Id,
CAST('<i>' + REPLACE(CountryName, ',', '</i><i>') + '</i>' AS XML) AS names
FROM @t
)

SELECT * FROM
(
SELECT 
Id,
x.i.value('.', 'VARCHAR(10)') AS Country,
'Country' + CAST(s.Number AS VARCHAR) AS CountryType
FROM cte
CROSS APPLY master..spt_values s 
CROSS APPLY names.nodes('//i[position()=sql:column("s.number")]') x(i)
WHERE s.type='p'
) a
PIVOT (
MAX(Country) FOR CountryType IN (Country1, Country2, Country3, Country4,Country5)
) pvt

Но с точки зрения производительности это очень плохо ... Я ищу лучший запрос, который может ускорить процесс (это может быть не мой подход xquery, а другой подход, использующий только cTE и не использующий RBar / процедурный / while цикл / курсор)

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

N.B. ~ Я не могу добавить индексирование в таблицу ... пожалуйста, рассмотрите этот пункт как ограничение для среды. Все, что мне нужно сделать, это только запрос.

N.B. ~ Может быть больше стран и не ограничиваться 5

Пожалуйста, помогите ....

Заранее спасибо

1 Ответ

0 голосов
/ 16 июня 2011

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

declare @T table(Id int,  CountryName varchar(50))
insert into @T values
(1,   'India,Australia,Singapore,Pakistan,Bangaladesh'),
(2,   'Norway,Argentina,Brazil,WestIndies,Burma')

select Id,
  substring(CountryName, 1, charindex(',', CountryName)-1) as Country1,
  parsename(T.N, 4) as Country2,
  parsename(T.N, 3) as Country3,
  parsename(T.N, 2) as Country4,
  parsename(T.N, 1) as Country5
from @T
  cross apply(select replace(stuff(CountryName, 1, charindex(',', CountryName), ''), ',', '.')) as T(N)

Если вы знаетечто у вас 8 стран, вы можете сделать это.

declare @T table(Id int,  CountryName varchar(100))
insert into @T values
(1,   'India,Australia,Singapore,Pakistan,Bangaladesh,Denmark,Germany,France'),
(2,   'Norway,Argentina,Brazil,WestIndies,Burma,South Africa,Spain,Portugal')


select Id,
  parsename(T1.N, 4) as Country1,
  parsename(T1.N, 3) as Country2,
  parsename(T1.N, 2) as Country3,
  parsename(T1.N, 1) as Country4,
  parsename(T2.N, 4) as Country5,
  parsename(T2.N, 3) as Country6,
  parsename(T2.N, 2) as Country7,
  parsename(T2.N, 1) as Country8
from @T
  cross apply(select charindex(',', CountryName, charindex(',', CountryName, charindex(',', CountryName, charindex(',', CountryName)+1)+1)+1)) as S(P)
  cross apply(select replace(substring(CountryName, 1, S.P-1), ',', '.')) as T1(N)
  cross apply(select replace(stuff(CountryName, 1, S.P, ''), ',', '.')) as T2(N)

Если вы не знаете, сколько у вас стран, вам нужно построить запрос динамически. Проклятие и благословения динамического SQL

...