我知道几乎没有足够的SQL来实现。我正在尝试让MS SQL显示一个记录集,应用程序可以通过很少的解析直接完成。
数据库结构如下:
因此,如果我想获得一个链接到特定服务的电子邮件地址列表,并使用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
email1@customer1.com Site A 1
email1@customer2.com Site B 2
email2@customer2.com Site B 2
email3@customer2.com Site B 2
email1@customer3.com Site C 3
email2@customer3.com Site C 3
email1@customer3.com Site D 3
email2@customer3.com 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 email1@customer1.com
2 Site B email1@customer2.com;email2@customer2.com;email3@customer2.com
3 Site C, Site D email1@customer3.com;email2@customer3.com
但是,如果我想通过在两个WHERE语句行中输入OR来从多个服务获取结果
where (serv.servicename = 'service 1' or serv.servicename = 'service 2' )
然后,结果将不会连接来自不同服务中同一客户的两个站点:
Customer Site Email
1 Site A email1@customer1.com
1 Site E email1@customer1.com
2 Site B email1@customer2.com;email2@customer2.com;email3@customer2.com
3 Site C, Site D email1@customer3.com;email2@customer3.com
我不太清楚它为什么不连接?我想我可能在做错了吗?
答案 0 :(得分: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) )
答案 1 :(得分: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