#sql #sql-server #xml #tsql #xquery
#sql #sql-сервер #xml #tsql #xquery
Вопрос:
Основное SequenceNum
внимание уделяется столбцу / полю. В этом поле текущий код подсчитывает и нумерует цепочки последовательностей между полностью совпадающими координатами X и Y. Например, в узле в пределах Parcel
ID = 1 есть одинаковые координаты с PointNum
1 и 4, 5 и 7. Таким образом, каждая последовательность между равными координатами получает одинаковое число в SequenceNum
поле, например 1-1-1-1, 2-2-2, 3-3-3-3 и т.д.. (И как общее правило: первое число точек всегда равно последнему числу точек внутри каждого элемента посылки).
Цель этого вопроса — объяснить ситуацию, когда отсутствуют внутренние последовательности полного совпадения координат. Никаких дополнительных цепочек между первым PointNum = 1 и последним PointNum = 1. Хотя технически эта ситуация в поле SequenceNum
эксплицируется как 1-then-null-null-null (для всех значений точек). Мне нужно расширить существующий код дополнительным условием, которое учитывало бы эту ситуацию, если она имеет место, и отметить переписать ее в значение ‘9999’ для всех нулей в SequenceNum
поле.
[UPD!] И также перепишите значение «1» в самой первой записи SequenceNum как «9999».
Присутствующий код (здесь он учитывает пример с наличием внутренних SequenceNum
последовательностей)
<Parcel ID="1">
<EntitySpatial>
<SpatialElement>
<SpelementUnit PointNum="1">
<Ordinate X="100.1" Y="-100.1"/>
</SpelementUnit>
<SpelementUnit PointNum="2">
<Ordinate X="100.2" Y="-100.2"/>
</SpelementUnit>
<SpelementUnit PointNum="3">
<Ordinate X="100.3" Y="-100.3"/>
</SpelementUnit>
<SpelementUnit PointNum="4">
<Ordinate X="100.1" Y="-100.1"/>
</SpelementUnit>
<SpelementUnit PointNum="5">
<Ordinate X="100.5" Y="-100.5"/>
</SpelementUnit>
<SpelementUnit PointNum="6">
<Ordinate X="100.6" Y="-100.6"/>
</SpelementUnit>
<SpelementUnit PointNum="7">
<Ordinate X="100.5" Y="-100.5"/>
</SpelementUnit>
<SpelementUnit PointNum="8">
<Ordinate X="100.8" Y="-100.8"/>
</SpelementUnit>
<SpelementUnit PointNum="9">
<Ordinate X="100.9" Y="-100.9"/>
</SpelementUnit>
<SpelementUnit PointNum="10">
<Ordinate X="100.11" Y="-100.11"/>
</SpelementUnit>
<SpelementUnit PointNum="1">
<Ordinate X="100.1" Y="-100.1"/>
</SpelementUnit>
</SpatialElement>
</EntitySpatial>
</Parcel>
<Parcel ID="2">
<EntitySpatial>
<SpatialElement>
<SpelementUnit PointNum="1">
<Ordinate X="200.1" Y="-200.1"/>
</SpelementUnit>
<SpelementUnit PointNum="2">
<Ordinate X="200.2" Y="-200.2"/>
</SpelementUnit>
<SpelementUnit PointNum="3">
<Ordinate X="200.1"" Y="-200.1"/>
</SpelementUnit>
<SpelementUnit PointNum="4">
<Ordinate X="200.4" Y="-200.4"/>
</SpelementUnit>
<SpelementUnit PointNum="5">
<Ordinate X="200.5" Y="-200.5"/>
</SpelementUnit>
<SpelementUnit PointNum="1">
<Ordinate X="200.1" Y="-200.1"/>
</SpelementUnit>
</SpatialElement>
</EntitySpatial>
</Parcel>
‘
WITH parseXml AS (
SELECT
base.value('@ID', 'VARCHAR(1000)') AS Parcel_ID,
outr.value('for $se in . return count(//SpatialElement[. << $se]) 1', 'INTEGER') AS SpatialElement_Count,
outr2.value('for $o in . return count(../SpelementUnit[. << $o]) 1', 'INTEGER') AS Ordinate_position,
outr2.value('@PointNum', 'INTEGER') AS PointNum,
outr2.value('(Ordinate/@X)[1]', 'NVARCHAR(100)') AS Ordinate_X,
outr2.value('(Ordinate/@Y)[1]', 'NVARCHAR(100)') AS Ordinate_Y
FROM @xml.nodes('Parcels/Parcel') as x(base)
OUTER APPLY base.nodes('EntitySpatial/SpatialElement') AS B(outr)
OUTER APPLY outr.nodes('SpelementUnit') AS C(outr2)
),
groups AS (
SELECT
Parcel_ID, Ordinate_X, Ordinate_Y,
--Exclude last row in parcel_id
MIN(CASE WHEN PointNum = Ordinate_position THEN Ordinate_position END) AS StartSequence,
MAX(CASE WHEN PointNum = Ordinate_position THEN Ordinate_position END) AS EndSequence,
ROW_NUMBER() OVER(PARTITION BY Parcel_ID
ORDER BY MIN(CASE WHEN PointNum = Ordinate_position THEN Ordinate_position END)) AS SequenceNum
FROM
parseXml
GROUP BY
Parcel_ID, Ordinate_X, Ordinate_Y
HAVING COUNT(*) > 1
)
SELECT
ref.Parcel_ID, ref.SpatialElement_Count, ref.Ordinate_X, ref.Ordinate_Y, ref.PointNum,
groups.SequenceNum
FROM
parseXml ref
LEFT JOIN groups
ON groups.StartSequence <= ref.Ordinate_position
AND groups.EndSequence >= ref.Ordinate_position
AND groups.Parcel_ID = ref.Parcel_ID
ORDER BY
ref.Parcel_ID, Ordinate_position;
результат этого кода
----------- ---------------------- ------------ ------------ --------------------------
| Parcel_ID | SpatialElement_Count | Ordinate_X | Ordinate_Y | PointNum | SequenceNum |
----------- ---------------------- ------------ ------------ --------------------------
| 1 | 1 | 100.1 | -100.1 | 1 | 1 |
| 1 | 1 | 100.2 | -100.2 | 2 | 1 |
| 1 | 1 | 100.3 | -100.3 | 3 | 1 |
| 1 | 1 | 100.1 | -100.1 | 4 | 1 |
| | | | | | |
| 1 | 1 | 100.5 | -100.5 | 5 | 2 |
| 1 | 1 | 100.6 | -100.6 | 6 | 2 |
| 1 | 1 | 100.5 | -100.5 | 7 | 2 |
| | | | | | |
| 1 | 1 | 100.8 | -100.8 | 8 | null |
| 1 | 1 | 100.9 | -100.9 | 9 | null |
| 1 | 1 | 100.11 | -100.11 | 10 | null |
| 1 | 1 | 100.1 | -100.1 | 1 | null |
| | | | | | |
| | | | | | |
| 2 | 2 | 200.1 | -200.1 | 1 | 3 |
| 2 | 2 | 200.2 | -200.2 | 2 | 3 |
| 2 | 2 | 200.1 | -200.1 | 3 | 3 |
| | | | | | |
| 2 | 2 | 200.4 | -200.4 | 4 | null |
| 2 | 2 | 200.5 | -200.5 | 5 | null |
| 2 | 2 | 200.1 | -200.1 | 1 | null |
----------- ---------------------- ------------ ------------ --------------------------
ЖЕЛАЕМЫЙ РЕЗУЛЬТАТ:
значение «9999» в SequenceNum
столбце для всех точек, если нет внутренних цепочек последовательностей
Комментарии:
1. итак, если SequenceNum равен нулю в конечном результате, вы хотите заменить его на 9999? Если это так, то замените
groups.SequenceNum
наCOALESCE(groups.SequenceNum, 9999) AS SequenceNum
2. @TimMylott Спасибо за этот намек… Но вопрос немного сложнее. Я уточню. Ваш вариант — это своего рода глобальное условие, которое заменяет все нули на 9999. В то время как мне нужно, чтобы все числа заменялись только при возникновении описанного случая (без дополнительных внутренних последовательностей). Это также означает, что в этом случае a) Что первая запись значения «1» в
SequenceNum
(которая такжеPointNum
равна = 1) также должна быть заменена на 9999 (помимо нулей). б) если внутренние цепочки сформированы (как в примере кода) — null должны быть сохранены (не заменены).