У меня есть таблица, которая определяет макет формы в XML. Внутри него есть <Control ...>
узлы, которые имеют такие атрибуты, как Id (GUID) и DataType (char) и т. д.
Эти XML-данные используются для создания формы во время выполнения, когда данные сохраняются, они записываются в XML в элементах с именем <Field ...>
, которые имеют атрибуты: Имя (соответствует GUID в идентификаторе узла управления) и Данные (содержит значение, которое был введен в контроль).
У нас есть проблема, из-за которой, когда вы .ToString объект Date, он использует настройки машины для формата даты. Таким образом, даты могут быть сохранены в любом возможном формате. Я обновил код, чтобы всегда сохранять даты в формате YYYY/MM/DD
, но теперь мне нужно обновить существующие данные в базе данных до YYYY/MM/DD
. Поскольку у нас нет возможности узнать, в каком формате была сохранена дата, мы просто предположим, что она была сохранена как MM/DD/YYYY
.
Итак, теперь моя проблема заключается в попытке обновить XML в SQL Server. Используя xquery и CROSS APPLY .nodes(), я могу написать запрос, чтобы найти все неправильно отформатированные даты, но я не могу понять, как их обновить.
Этот сценарий SQL создаст табличные переменные и заполнит их некоторыми тестовыми данными, а также имеет запрос, который вернет значения неправильных дат. последняя закомментированная часть - это то, как я пытался обновить их до нового формата YYYY/MM/DD
, но если вы раскомментируете его, вы увидите, что это не работает.
У кого-нибудь есть идеи?
P.S. Это можно сделать только в сценарии SQL. Я знаю, что было бы очень легко написать функцию в .NET, которая считывает все данные xml и обновляет атрибуты, а затем сохраняет данные обратно в базу данных, но в данном случае это невозможно по следующим причинам.
DECLARE @Form AS Table
(
FormID INT,
FormDataXML XML
);
DECLARE @ScreenData AS Table
(
ScreenDataID INT,
FormID INT,
ScreenDataXML XML
);
DECLARE @ControlsToUpdate AS TABLE
(
FormID INT,
ControlID char(36),
DataType CHAR(1)
);
INSERT INTO @Form
VALUES (1, '<Form><Control Id="00000000-0000-0000-0000-000000000000" DataType="D" /><Control Id="00000000-0000-0000-0000-000000000001" DataType="N" /></Form>');
INSERT INTO @Form
VALUES (2, '<Form><Control Id="00000000-0000-0000-0000-000000000002" DataType="D" /><Control Id="00000000-0000-0000-0000-000000000003" DataType="D" /></Form>');
INSERT INTO @ScreenData
VALUES (1, 1, '<ScreenData><Field Name="00000000-0000-0000-0000-000000000000" Data="01/31/2012" /><Field Name="00000000-0000-0000-0000-000000000001" Data="1234.56" /></ScreenData>');
INSERT INTO @ScreenData
VALUES (2, 1, '<ScreenData><Field Name="00000000-0000-0000-0000-000000000000" Data="02/28/2013" /><Field Name="00000000-0000-0000-0000-000000000001" Data="0" /></ScreenData>');
INSERT INTO @ScreenData
VALUES (3, 2, '<ScreenData><Field Name="00000000-0000-0000-0000-000000000002" Data="03/31/2013" /><Field Name="00000000-0000-0000-0000-000000000003" Data="04/30/2013" /></ScreenData>');
INSERT INTO @ScreenData
VALUES (4, 2, '<ScreenData><Field Name="00000000-0000-0000-0000-000000000002" Data="2013/05/31" /><Field Name="00000000-0000-0000-0000-000000000003" Data="2013/06/30" /></ScreenData>');
--Data treated as scheduled items
INSERT INTO @ScreenData
VALUES (5, 2, '<ScreenData><Item><Field Name="00000000-0000-0000-0000-000000000002" Data="01/01/2012" /><Field Name="00000000-0000-0000-0000-000000000003" Data="02/02/2012" /></Item><Item><Field Name="00000000-0000-0000-0000-000000000002" Data="03/03/2012" /><Field Name="00000000-0000-0000-0000-000000000003" Data="04/04/2012" /></Item></ScreenData>')
INSERT INTO @ControlsToUpdate
SELECT FormID,
data.control.value('@Id', 'char(36)'),
data.control.value('@DataType', 'char(1)')
FROM @Form
CROSS APPLY FormDataXML.nodes('//Control') data(control)
WHERE data.control.value('@DataType', 'char(1)') = 'D';
--This will display the ScreenDataID, FormID, ControlID, and current Date value for dates that are in the old mm/dd/yyyy format
SELECT d.ScreenDataID, d.FormID, c.ControlID,
data.field.value('@Data', 'char(10)') as Date
FROM @ScreenData d
CROSS APPLY d.ScreenDataXML.nodes('//Field') as data(field)
INNER JOIN @ControlsToUpdate c ON c.ControlID = data.field.value('@Name', 'CHAR(36)')
AND d.FormID = c.FormID
WHERE data.field.value('@Data', 'char(10)')
LIKE '[01][0123456789]/[0123][0123456789]/[12][0123456789][0123456789][0123456789]';
--UPDATE d
--SET data.field.modify('replace value of (/@Data) with "' +
-- SUBSTRING(data.field.value('@Data', 'char(10)'), 7, 4) + '/' +
-- SUBSTRING(data.field.value('@Data', 'char(10)'), 1, 2) + '/' +
-- SUBSTRING(data.field.value('@Data', 'char(10)'), 4, 2) + '"')
--FROM @ScreenData d
--CROSS APPLY d.ScreenDataXML.nodes('//Field') as data(field)
--INNER JOIN @ControlsToUpdate c ON c.Id = data.field.value('@Name', 'CHAR(36)')
-- AND d.FormID = c.FormID
--WHERE data.field.value('@Data', 'varchar(MAX)')
--LIKE '[01][0123456789]/[0123][0123456789]/[12][0123456789][0123456789][0123456789]';
GO
--Edit-- XML-файл в @ScreenData также может содержать <Item>
узлов, которые содержат <Field>
узлов. Когда это произойдет, у вас будет несколько <Field>
узлов с одинаковым значением атрибута Name. Это тот случай, когда на экране есть список элементов, у вас будет несколько элементов, каждый из которых ссылается на один и тот же элемент управления, но имеет свои собственные значения. ScreenDataID 5 показывает это.