مسار SQL XML مع أطفال مختلفين
سؤال
لقد فعلت الكثير من عبارات مسار XML ، لكن هذا يهرب مني أو قد لا يكون ممكنًا مع العديد من الأطفال المختلفين.
يجب أن تبدو النتيجة النهائية هكذا
<Process>
<TaskList>
<SqlTask Name="Get Report Parameters">
<StoredProcName>GetReportParameters</StoredProcName>
<ConnectionName>Local</ConnectionName>
<DataTableName>DistributionList</DataTableName>
<Parameters>
<Parameter>
<Name>ReportName</Name>
<Value>TheReprot</Value>
<Type>String</Type>
</Parameter>
</Parameters>
</SqlTask>
<LoopTask Name="Loop Report Creation" ContainerKey="DistributionList">
<TaskList>
<ReportTask Name="Report In Loop">
</ReportTask>
</TaskList>
</LoopTask>
<SqlTask Name="Get Email Addresses">
<StoredProcName>GetMailingAddress</StoredProcName>
<ConnectionName>Local</ConnectionName>
<DataTableName>EmailList</DataTableName>
</SqlTask>
<LoopTask Name="Loop Mail Creation" ContainerKey="EmailList">
<TaskList>
<MailTask Name="Send Email In Loop">
</MailTask>
</TaskList>
</LoopTask>
</TaskList>
</Process>
فيما يلي بعض جدول الاختبار والبيانات التي لدي حتى الآن. السؤال هو في الحقيقة كيف يمكنني عرض عقد الأطفال المختلفة تحت نفس الجذر. وهل يمكنني استنباط اسم علامة من قيمة العمود؟
CREATE TABLE #TASK (
TaskId INT IDENTITY(1,1)
, ProcessId INT
, TaskType VARCHAR(255)
, TaskName VARCHAR(255)
, ContainerKey VARCHAR(255)
, ParentTaskId INT
)
CREATE TABLE #TASK_PARAMETERS
(
TaskId INT
, Name VARCHAR(255)
, Value VARCHAR(MAX)
, [Type] VARCHAR(128)
)
CREATE TABLE #TASK_DETAILS
(
TaskId INT
, DetailName VARCHAR(255)
, DetailValue VARCHAR(MAX)
)
DECLARE @TaskId AS INT
DECLARE @ParentTaskId AS INT
INSERT INTO #TASK
(
ProcessId
, TaskType
, TaskName
, ContainerKey
, ParentTaskId
)
VALUES
(
0
, 'SqlTask'
, 'Get Report Parameters'
, NULL
, NULL
)
SET @TaskId = @@IDENTITY
INSERT INTO #TASK_DETAILS
(
TaskId
, DetailName
, DetailValue
)
VALUES
(
@TaskId
, 'StoredProceName'
, 'GetReportParamters'
)
INSERT INTO #TASK_DETAILS
(
TaskId
, DetailName
, DetailValue
)
VALUES
(
@TaskId
, 'ConnectionName'
, 'Local'
)
INSERT INTO #TASK_DETAILS
(
TaskId
, DetailName
, DetailValue
)
VALUES
(
@TaskId
, 'DataTableName'
, 'DistributionList'
)
INSERT INTO #TASK_PARAMETERS
(
TaskId
, Name
, Value
, [Type]
)
VALUES
(
@TaskId
, 'ReportName'
, 'TheReprot'
, 'String'
)
INSERT INTO #TASK
(
ProcessId
, TaskType
, TaskName
, ContainerKey
, ParentTaskId
)
VALUES
(
0
, 'LoopTask'
, 'Loop Report Creation'
, 'DistributionList'
, NULL
)
SET @ParentTaskId = @@IDENTITY
INSERT INTO #TASK
(
ProcessId
, TaskType
, TaskName
, ContainerKey
, ParentTaskId
)
VALUES
(
0
, 'ReportTask'
, 'Report In Loop'
, NULL
, @ParentTaskId
)
INSERT INTO #TASK
(
ProcessId
, TaskType
, TaskName
, ContainerKey
, ParentTaskId
)
VALUES
(
0
, 'SqlTask'
, 'Get Email Addresses'
, NULL
, NULL
)
SET @TaskId = @@IDENTITY
INSERT INTO #TASK_DETAILS
(
TaskId
, DetailName
, DetailValue
)
VALUES
(
@TaskId
, 'StoredProceName'
, 'GetMailingAddress'
)
INSERT INTO #TASK_DETAILS
(
TaskId
, DetailName
, DetailValue
)
VALUES
(
@TaskId
, 'ConnectionName'
, 'Local'
)
INSERT INTO #TASK_DETAILS
(
TaskId
, DetailName
, DetailValue
)
VALUES
(
@TaskId
, 'DataTableName'
, 'EmailList'
)
INSERT INTO #TASK
(
ProcessId
, TaskType
, TaskName
, ContainerKey
, ParentTaskId
)
VALUES
(
0
, 'LoopTask'
, 'Loop Mail Creation'
, 'EmailList'
, NULL
)
SET @ParentTaskId = @@IDENTITY
INSERT INTO #TASK
(
ProcessId
, TaskType
, TaskName
, ContainerKey
, ParentTaskId
)
VALUES
(
0
, 'MailTask'
, 'Send Email In Loop'
, NULL
, @ParentTaskId
)
SELECT *
FROM #TASK
SELECT *
FROM #TASK_PARAMETERS
SELECT *
FROM #TASK_DETAILS
المحلول
صحيح ، لديك العديد من المشكلات التي يجب التغلب عليها مع عينة!
أولاً ، سأقدم لك الإجابة ، على الرغم من أنه من أجل معالجة بشكل صحيح بشكل صحيح ، يجب أن تكون وظيفة متكررة ، لذلك كان يجب إنشاء بيانات الاختبار التي قدمتها في جداول دائمة بدلاً من مؤقت (أبسط) وبعد ذلك أنا " أشر إلى بعض التقنيات المفيدة التي استخدمتها في حل المشكلة.
ALTER FUNCTION GetTasks (@ParentId varchar(255)= NULL)
RETURNS
XML
BEGIN
DECLARE @ReturnXML XML
SELECT @ReturnXML =
(
SELECT
(
SELECT
CONVERT(XML,
--Main task start tag
'<'+master_t.TaskType+' Name="'+master_t.TaskName+'">'+
CONVERT(VARCHAR(MAX),
(
SELECT
dbo.GetTasks(master_t.TaskId),
(
SELECT
CONVERT(XML,'<'+DetailName+'>'+DetailValue+'</'+DetailName+'>')
FROM
TASK_DETAILS t
WHERE
TaskId = master_t.TaskId
FOR XML PATH(''),Type
),
(
SELECT Name,Value,Type FROM TASK_PARAMETERS t
WHERE TaskId=master_t.TaskId
FOR XML PATH('Parameter'),Type
) 'Parameters'
FOR XML PATH(''),Type
)
)
+
--Main task end tag
'</'+master_t.TaskType+'>'
)
FROM
TASK master_t
WHERE
--Effectively ignore the parentId field if it is not passed.
ISNULL(ParentTaskId,'') = CASE WHEN @ParentId IS NULL THEN '' ELSE @ParentId END
FOR XML PATH(''),Type
) 'TaskList' FOR XML PATH(''),Type
)
RETURN @ReturnXML
END
GO
استدعاء هذه الوظيفة مثل هذه:
SELECT dbo.GetTasks(NULL)
صحيح التقنيات التي أعتقد أنها تستحق الإشارة إليها هي:
أ) يمكنك إنشاء عقد XML يدويًا عن طريق ببساطة بنائها من السلاسل- وهذا مفيد إذا كانت أسماء العقدة في الجدول. الشيء الوحيد الذي يجب أن تكون على دراية به هو أن تضع علامة مفتوحة وإغلاق حول كتلة ، فمن المحتمل أن تضطر إلى تحويل الكتلة إلى سلسلة أولاً ، وتصلب على العلامات ، ثم تحويل الأمر بأكمله إلى XML (PetcemeMeal لن تعمل كوظيفة التحويل إلى XML تتوقع منك تقديم XML المشكلة جيدًا.
ب) يجب عليك أحيانًا أن تعشش الأشياء بين قوسين لتحقيق علامة حول جميع الأدوات الفرعية ... مثال يجعل هذا أكثر وضوحًا:
SELECT
TaskName
FROM TASK t
FOR XML PATH('SomeRoot')
سوف تنتج:
<SomeRoot>
<TaskName>Get Report Parameters</TaskName>
</SomeRoot>
<SomeRoot>
<TaskName>Loop Report Creation</TaskName>
</SomeRoot>
<SomeRoot>
<TaskName>Report In Loop</TaskName>
</SomeRoot>
<SomeRoot>
<TaskName>Get Email Addresses</TaskName>
</SomeRoot>
<SomeRoot>
<TaskName>Loop Mail Creation</TaskName>
</SomeRoot>
<SomeRoot>
<TaskName>Send Email In Loop</TaskName>
</SomeRoot>
للحصول على "Someroot" لتظهر حوله ، يمكنك القيام بذلك:
SELECT
(
SELECT
TaskName
FROM TASK t
FOR XML PATH(''),Type
)
FOR XML PATH('SomeRoot')
إذا كان اسم العقدة ثابتًا (لاحظ مسار XML ('')،يكتب, ، وهو ما يضمن أساسًا أن مسار XML يعيد بيانات نوع XML لمزيد من المعالجة ولا يفلت منه)
إذا لم يكن اسم العقدة ثابتًا ، فأنت عالق بشيء من هذا القبيل ، مع الحاجة إلى التحويل إلى السلسلة من وإلى سلسلة لجعلها تعمل.
SELECT
CONVERT(XML,
'<'+DynamicName+'>' +
CONVERT(VARCHAR(MAX),
(
SELECT
TaskName
FROM TASK t
FOR XML PATH(''),Type
)
) +
'</'+DynamicName+'>'
)
FROM
(SELECT 'Test' as DynamicName) a
ج) فيما يتعلق بسؤالك حول جعل علامات الأطفال المختلفين تظهر على نفس المستوى ، إنه تافهة إلى حد ما ، وعليك فقط أن تتذكر أن المشكلة المعتادة لطبقات متعددة من Select تتوقف عن أن تكون مشكلة في XML كما تحدد XML فقط أ إرجاع أ كائن XML واحد. يمكنك بعد ذلك استخدام مسار XML لدمج هذه النتائج في شجرة أيضًا.
على سبيل المثال
SELECT
(SELECT top 1 * FROM TASK FOR XML PATH(''),Type),
(SELECT top 1 * FROM TASK_DETAILS FOR XML PATH(''),Type)
سيعود صفًا واحدًا مع عمودين ولكن إذا قمت بتطبيق مسار XML ('') على الكل ، فقد قمت بدمجهما على نفس المستوى
SELECT
(SELECT top 1 * FROM TASK FOR XML PATH(''),Type),
(SELECT top 1 * FROM TASK_DETAILS FOR XML PATH(''),Type)
FOR XML PATH('Root')
د) يتم تحويل أسماء الأعمدة إلى عقد لك إذا كان عن طريق مسار XML. السمات سهلة للغاية من حيث أنك فقط تعطي العمود اسم مستعار وهو مسار XSL المناسب على سبيل المثال mynodename MyAttributeName "من الواضح أن هذا يمنع السمات التي يتم تسميتها أيضًا ديناميكيًا. لذلك ، في هذا المثال ، قمت للتو ببناء XML من الأوتار مرة أخرى. هذا هو السبب في أن أسماء العقدة الديناميكية هي فكرة سيئة- فأنت تسمح بشكل أساسي لروتينك بإنشاء أسماء سمات جديدة وأسماء العقدة عبر البيانات في الجدول ... وهذا يعني أنه لا يمكنك إنشاء مخطط لائق لروتينك AS AS الخاص بك أنت لا تعرف مقدمًا ما هي البيانات التي قد تكون في الجدول ...
الانتقال :)
لذلك ، نظرًا لتلك اللبنات الأساسية ، فإن أسهل شيء يجب القيام به هو العمل من أعمق مستوى ، وبنشته بلوك ، ثم يُمزج كما هو أعلاه.
لقد فعلت ذلك من أجل استعلامك ، وأدركت في النهاية أنه لجعله يعمل بشكل هرمي (أي مستويات متداخلة) كان عليّ أن أكتب هو كدالة تعود إلى XML ، والتي تسمى تمرير الأمومة إليها (بحيث تعرف الوظيفة ماذا تفعل تصفية النتيجة المحددة إلى). سيموت هذا موتًا فظيعًا إذا كان التسلسل الهرمي سيئًا ودائمًا.
حسنًا- نأمل أن يكون هناك شيء ما يمكنك العمل معه. هذا هو حل XML المسار () الموجود - هناك طرق XML بديلة يمكن أن تكون مفيدة في المواقف المختلفة.