2014-10-07 76 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 
[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路徑來連接的結果類似的問題的答案。這是我用來獲取一個有效的解決方案查詢:

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

謝謝,我不認爲「爲Table」是正確的語法? – Jimms 2014-10-08 01:54:43

+0

是的,我認爲是這樣的:/你可以複製整個第一個查詢,而不是使用table1,看看它是否工作。否則,我會看看那個明天,因爲我在牀上atm:頁 – Alex 2014-10-08 02:00:50