Нормализация таблицы (разделяет поля, разделенные запятыми, на отдельные записи)
У меня есть таблица вроде этого:
Устройство
DeviceId Parts
1 Part1, Part2, Part3
2 Part2, Part3, Part4
3 Part1
Я хотел бы создать таблицу "Parts", экспортировать данные из столбца Parts в новую таблицу. После этого я закрою столбец "Детали"
Ожидаемый результат
<сильные > Части
PartId PartName
1 Part1
2 Part2
3 Part3
4 Part4
DevicePart
DeviceId PartId
1 1
1 2
1 3
2 2
2 3
2 4
3 1
Могу ли я сделать это в SQL Server 2008 без использования курсоров?
Ответы
Ответ 1
- Настройка:
declare @Device table(DeviceId int primary key, Parts varchar(1000))
declare @Part table(PartId int identity(1,1) primary key, PartName varchar(100))
declare @DevicePart table(DeviceId int, PartId int)
insert @Device
values
(1, 'Part1, Part2, Part3'),
(2, 'Part2, Part3, Part4'),
(3, 'Part1')
- Script:
declare @DevicePartTemp table(DeviceId int, PartName varchar(100))
insert @DevicePartTemp
select DeviceId, ltrim(x.value('.', 'varchar(100)'))
from
(
select DeviceId, cast('<x>' + replace(Parts, ',', '</x><x>') + '</x>' as xml) XmlColumn
from @Device
)tt
cross apply
XmlColumn.nodes('x') as Nodes(x)
insert @Part
select distinct PartName
from @DevicePartTemp
insert @DevicePart
select tmp.DeviceId, prt.PartId
from @DevicePartTemp tmp
join @Part prt on
prt.PartName = tmp.PartName
- Результат:
select *
from @Part
PartId PartName
----------- ---------
1 Part1
2 Part2
3 Part3
4 Part4
select *
from @DevicePart
DeviceId PartId
----------- -----------
1 1
1 2
1 3
2 2
2 3
2 4
3 1
Ответ 2
Вам понадобится таблица Tally, чтобы выполнить это без курсора.
Следуйте инструкциям, чтобы создать таблицу таблиц: Таблицы Tally by Jeff Moden
Этот script помещает таблицу в вашу базу данных Temp, поэтому вы, вероятно, захотите изменить оператор "Использовать БД"
Затем вы можете запустить script ниже, чтобы вставить разбивку устройств и частей в таблицу temp. Затем вы можете присоединиться к своей части таблицы именем части (получить идентификатор) и вставить в новую таблицу DevicePart.
select *,
--substring(d.parts, 1, t.n)
substring(d.parts, t.n, charindex(', ', d.parts + ', ',t.n) - t.n) 'Part'
into #devicesparts
from device d
cross join tally t
where t.n < (select max(len(parts))+ 1 from device)
and substring(', ' + d.parts, t.n, 1) = ', '
Ответ 3
Посмотрите на использование fn_Split, чтобы создать переменную таблицы из значений, разделенных запятыми.
Затем вы можете использовать это для вставки вашей вставки.
EDIT: На самом деле, я думаю, вам может понадобиться курсор. Если оставить этот ответ, то fn_Split поможет.
Ответ 4
Если на устройство имеется максимальное количество частей, тогда да, это можно сделать без курсора, но это довольно сложно.
По существу, создайте таблицу (или представление или подзапрос), которая имеет идентификатор DeviceID и один столбец PartID для каждого возможного индекса в строке PartID. Это можно сделать, сделав колонки столбцов PartID, используя fn_split или другой метод по вашему выбору. Оттуда вы делаете множественный самосоединение этой таблицы с одной таблицей в самосоединении для каждого столбца PartID. Каждая таблица в self-UNION имеет только один из столбцов PartID, включенных в список выбора запроса для таблицы.