2014-10-07 3 views
0

Я знаю, что недостаточно SQL для прохождения. Я пытаюсь заставить MS SQL отображать набор записей, который приложение может выполнять непосредственно с небольшим разбором.Использование XML PATH для конкатенации результатов из нескольких предложений WHERE

база данных структурирована следующим образом:

  • таблица клиентов
  • Таблица TechContacts
  • Таблица услуг
  • Таблица сайтов
  • Каждая запись в TechContact является FK назад к заказчику
  • Каждая запись FK для клиента и обслуживания
  • Каждая услуга может быть связана с одним или несколькими Сайтами от нескольких клиентов.

Так что, если я хочу, чтобы получить список адресов электронной почты, которые связаны с конкретной службой, и получить набор моих результатов только с помощью INNER JOIN, это будет выглядеть следующим образом:

SELECT tc.emailaddress as 'Email Address', s.sitename as 'Affected Site', c.CustomerName as 'Customer Name' 
FROM techcontact as tc 
INNER JOIN customer as c 
on tc.customernumber = c.customernumber 
INNER JOIN site as s 
on c.customernumber = s.customernumber 
INNER JOIN dbo.service as serv 
on s.serviceid = serv.serviceid 
INNER JOIN sitetype as st 
on s.sitetype = st.SiteTypeID 

where serv.servicename = 'Service 1' 
and st.SiteTypeID = 1 
and s.enabled = 1 
order by s.SiteName asc 

Даст я строка для каждого адреса электронной почты:

Email Address   Site Affected Customer Name 
[email protected] Site A   1 
[email protected] Site B   2 
[email protected] Site B   2 
email3[email protected] Site B   2 
[email protected] Site C   3 
[email protected] Site C   3 
[email protected] Site D   3 
[email protected] Site D   3 

После некоторых поисков, я нашел ответ на подобный вопрос, который используется XML PATH, чтобы сцепить результаты. Это запрос, я использовал для получения рабочего раствора:

Select distinct c.customernumber, 
substring(

    (
     Select ';'+tc.emailaddress AS [text()] 
     From dbo.techcontact tc 
     Where tc.customernumber = c.customernumber 
     For XML PATH ('') 
    ), 2, 1000) [Emails], 
substring(

    (
     Select distinct ', '+s.SiteName AS [text()] 
     From dbo.Site s 
     inner join service 
     on s.serviceid = serv.serviceid 
     where (serv.servicename = 'service 1') 
     and s.SiteType = 1 
     and s.CustomerNumber = c.CustomerNumber 
     For XML PATH ('') 
    ), 2, 1000) [Sites] 
From dbo.customer c 
INNER JOIN site as s 
on c.customernumber = s.customernumber 
INNER JOIN dbo.service as serv 
on s.serviceid = serv.serviceid 
INNER JOIN dbo.TechContact as tc 
on tc.CustomerNumber = c.CustomerNumber 
where (serv.servicename = 'service 1') 
and s.SiteType = 1 

Который дал мне этот результат: который совершенен:

Customer Sites    Email 
1   Site A   [email protected] 
2   Site B   [email protected];[email protected];[email protected] 
3   Site C, Site D [email protected];[email protected] 

Однако, если я хочу, чтобы получить результаты из нескольких служб, введя ИЛИ в двух строках заявления WHERE, как так

where (serv.servicename = 'service 1' or serv.servicename = 'service 2') 

Тогда результат не будет конкатенация, где есть два участка от одного клиента в различных службах:

Customer Site   Email 
1   Site A   [email protected] 
1   Site E   [email protected] 
2   Site B   [email protected];[email protected];[email protected] 
3   Site C, Site D [email protected];[email protected] 

Я не уверен, почему это не конкатенирование? Я думаю, что, возможно, я ошибаюсь.

ответ

0

я в конечном итоге получить вокруг него, вставив весь набор результатов в другую таблицу, используя табличную переменную, а затем с помощью XML PATH для выберите из этого. Он добавляет дополнительный шаг, который я надеялся избежать, но конечный результат - это то, что я хочу.

Запрос:

-- Drop the table before we attempt to use it. 
IF OBJECT_ID('zzz1', 'U') IS NOT NULL 
DROP TABLE zzz1 
GO 

--Table variable will be inserted in via a form, called @AffectedServices, but for the sake of testing we will insert them here. 
declare @AffectedServices table 
(
    ServiceName varchar(1000) 
) 
insert into @AffectedServices values ('Service 1') 
insert into @AffectedServices values ('Service 2') 
insert into @AffectedServices values ('Service 3') 

--select into the new table. The table has some primary keys that don't get displayed. 
select c.customernumber, s.CustomerNumber as 'sCustomerNumber', s.sitename, tc.CustomerNumber as 'tcCustomerNumber', tc.emailaddress 
into zzz1 
FROM TechContact as tc 
INNER JOIN customer as c 
    on tc.customernumber = c.customernumber 
INNER JOIN site as s 
    on c.customernumber = s.customernumber 
INNER JOIN dbo.service as serv 
    on s.serviceid = serv.serviceid 
INNER JOIN sitetype as st 
    on s.sitetype = st.SiteTypeID 
INNER JOIN @AffectedServices as AfSe 
on serv.ServiceName = AfSe.ServiceName 
WHERE serv.servicename = AfSe.ServiceName 
and st.SiteTypeID = 1 

--Now we can concatenate the results without using extra WHERE/OR clauses. 
Select T1.Customernumber 
    , Stuff(
     (
     Select distinct ', ' + T2.SiteName 
     From zzz1 As T2 
     Where T2.CustomerNumber = T1.CustomerNumber 
     --Order By T2.SiteName 
     For Xml Path(''), type 
     ).value('.', 'nvarchar(max)'), 1, 2, '') As Sites 
     , Stuff(
     (
     Select distinct ', ' + T2.EmailAddress 
     From zzz1 As T2 
     Where T2.CustomerNumber = T1.CustomerNumber 
     --Order By T2.EmailAddress 
     For Xml Path(''), type 
     ).value('.', 'nvarchar(max)'), 1, 2, '') As EmailAddresses 
From zzz1 As T1 
Group By T1.CustomerNumber 
0

Это, вероятно, не является оптимальным, но это будет решить вашу проблему:

Select distinct c.customernumber, 
substring(

(
    Select ';'+tc.emailaddress AS [text()] 
    From dbo.techcontact tc 
    Where tc.customernumber = c.customernumber 
    For XML PATH ('') 
), 2, 1000) [Emails], 
substring(

    (
     Select distinct ', '+s.SiteName AS [text()] 
     From dbo.Site s 
     inner join service 
     on s.serviceid = serv.serviceid 
     where (serv.servicename = 'service 1') 
     and s.SiteType = 1 
     and s.CustomerNumber = c.CustomerNumber 
     For XML PATH ('') 
    ), 2, 1000) [Sites] 
From dbo.customer c 
INNER JOIN site as s 
on c.customernumber = s.customernumber 
INNER JOIN dbo.service as serv 
on s.serviceid = serv.serviceid 
INNER JOIN dbo.TechContact as tc 
on tc.CustomerNumber = c.CustomerNumber 
where (serv.servicename = 'service 1' AND serv.servicename = 'service 2') 
and s.SiteType = 1) 
UNION 
Select distinct c.customernumber, 
substring(

(
    Select ';'+tc.emailaddress AS [text()] 
    From dbo.techcontact tc 
    Where tc.customernumber = c.customernumber 
    For XML PATH ('') 
), 2, 1000) [Emails], 
substring(

    (
     Select distinct ', '+s.SiteName AS [text()] 
     From dbo.Site s 
     inner join service 
     on s.serviceid = serv.serviceid 
     where (serv.servicename = 'service 1') 
     and s.SiteType = 1 
     and s.CustomerNumber = c.CustomerNumber 
     For XML PATH ('') 
    ), 2, 1000) [Sites] 
From dbo.customer c 
INNER JOIN site as s 
on c.customernumber = s.customernumber 
INNER JOIN dbo.service as serv 
on s.serviceid = serv.serviceid 
INNER JOIN dbo.TechContact as tc 
on tc.CustomerNumber = c.CustomerNumber 
where (serv.servicename = 'service 1') 
and s.SiteType = 1 
Except (Select distinct c.customernumber, 
substring(

(
    Select ';'+tc.emailaddress AS [text()] 
    From dbo.techcontact tc 
    Where tc.customernumber = c.customernumber 
    For XML PATH ('') 
), 2, 1000) [Emails], 
substring(

    (
     Select distinct ', '+s.SiteName AS [text()] 
     From dbo.Site s 
     inner join service 
     on s.serviceid = serv.serviceid 
     where (serv.servicename = 'service 1') 
     and s.SiteType = 1 
     and s.CustomerNumber = c.CustomerNumber 
     For XML PATH ('') 
    ), 2, 1000) [Sites] 
From dbo.customer c 
INNER JOIN site as s 
on c.customernumber = s.customernumber 
INNER JOIN dbo.service as serv 
on s.serviceid = serv.serviceid 
INNER JOIN dbo.TechContact as tc 
on tc.CustomerNumber = c.CustomerNumber 
where (serv.servicename = 'service 1' AND serv.servicename = 'service 2') 
and s.SiteType = 1)) 
UNION 
     Select distinct ', '+s.SiteName AS [text()] 
     From dbo.Site s 
     inner join service 
     on s.serviceid = serv.serviceid 
     where (serv.servicename = 'service 1') 
     and s.SiteType = 1 
     and s.CustomerNumber = c.CustomerNumber 
     For XML PATH ('') 
    ), 2, 1000) [Sites] 
From dbo.customer c 
INNER JOIN site as s 
on c.customernumber = s.customernumber 
INNER JOIN dbo.service as serv 
on s.serviceid = serv.serviceid 
INNER JOIN dbo.TechContact as tc 
on tc.CustomerNumber = c.CustomerNumber 
where (serv.servicename = 'service 2') 
and s.SiteType = 1 
Except (Select distinct c.customernumber, 
substring(

(
    Select ';'+tc.emailaddress AS [text()] 
    From dbo.techcontact tc 
    Where tc.customernumber = c.customernumber 
    For XML PATH ('') 
), 2, 1000) [Emails], 
substring(

    (
     Select distinct ', '+s.SiteName AS [text()] 
     From dbo.Site s 
     inner join service 
     on s.serviceid = serv.serviceid 
     where (serv.servicename = 'service 1') 
     and s.SiteType = 1 
     and s.CustomerNumber = c.CustomerNumber 
     For XML PATH ('') 
    ), 2, 1000) [Sites] 
From dbo.customer c 
INNER JOIN site as s 
on c.customernumber = s.customernumber 
INNER JOIN dbo.service as serv 
on s.serviceid = serv.serviceid 
INNER JOIN dbo.TechContact as tc 
on tc.CustomerNumber = c.CustomerNumber 
where (serv.servicename = 'service 1' AND serv.servicename = 'service 2') 
and s.SiteType = 1)) 
+0

Спасибо, я не думаю, что синтаксис 'AS table1' правильно? – Jimms

+0

Да, я так и думал:/вы можете скопировать весь первый запрос вместо использования таблицы1 и посмотреть, работает ли он. В противном случае я буду смотреть на то, что tommorow, так как im в постели atm: p – Alex

Смежные вопросы