2013-10-28 179 views
3

晚上好,基于多对多筛选器选择

我有一个类似于下图的表格布局。 用户表正在存储我的大部分信息。对于每个用户,我也可以有一个不确定数量的首选项位置选择,我将其存储在交汇表中,如图所示。

Data table layout

  1. 当管理员来产生一个报告,他们将使用偏好和位置的选择就像一个过滤器。例如,他们可以选择Preference1和Preference3以及UserLocation2和UserLocation4,报告应该只显示至少有一个偏好和至少一个位置的用户。是否有可能在一个SQL select语句中执行此操作?我正在使用SQL Server 2008 R2。

  2. 假设一个用户记录符合上述的返回条件,是否有办法显示所有的首选项和位置,并连接到一个新列中。我已经想出了如何为单个用户获取连接结果,但不知道它是否也可以作为同一个SQL select语句的一部分来完成。

这是我返回以逗号分隔的喜好,为个人用户名...

DECLARE @concatlist VARCHAR(MAX) 
SELECT @concatlist = COALESCE(@concatlist+', ', '') + dbo.Preference.Title 
FROM dbo.UserPreference 
LEFT OUTER JOIN dbo.Preference 
ON dbo.UserPreference.PreferenceID = dbo.Preference.PreferenceID 
WHERE dbo.UserPreference.UserID = 5 
SELECT @concatlist as OutputColumn 

任何指针将是巨大的。我已经花了半天的时间在这方面,虽然我可以做到这一点,但无法在一个声明中找到办法。

感谢,

回答

2

你可以试试这个

WITH UPreference AS (
    SELECT u.*,p.* 
    FROM Users u 
    INNER JOIN UserPreference up 
     ON u.UserID = up.UserID 
    INNER JOIN Preference p 
     ON up.PreferenceID = p.PreferenceID 
) 
, ULocation AS (
    SELECT u.*,l.* 
    FROM Users u 
    INNER JOIN UserLocation ul 
     ON u.UserID = ul.UserID 
    INNER JOIN Location l 
     ON l.LocationID = ul.LocationID 
) 
SELECT u.* 
    ,AllPreferences = STUFF((SELECT ',' + up.Title FROM UPreference up WHERE up.UserID = u.UserID FOR XML PATH('')) ,1,1,'') 
    ,AllLocations = STUFF((SELECT ',' + ul.[Name] FROM ULocation ul WHERE ul.UserID = u.UserID FOR XML PATH('')) ,1,1,'') 
FROM Users u 
WHERE 
    EXISTS(SELECT 1 FROM UPreference up WHERE up.UserID = u.UserID AND up.Title IN ('Preference1','Preference3') 
AND 
    EXISTS(SELECT 1 FROM ULocation ul WHERE ul.UserID = u.UserID AND ul.[Name] IN ('Location2','Location4') 
+0

感谢埃里克 - 一些调整,这工作得很好,而不需要比较EXISTS语句中的特定偏好或位置。 – Simon

1

如果你想使用XML数据类型来表示你的选择偏好/位置,那么答案应该很简单。

我相信这应该解决您的第一个问题:

DECLARE 
    @prefs xml = '<a><i id="1" /><i id="3" /></a>', 
    @locs xml = '<a><i id="2" /><i id="3" /></a>' 

;WITH p AS (
    SELECT 
     id = c.value('./@id', 'int') 
    FROM @prefs.nodes('/a/i') T(c) 
) 
,l AS (
    SELECT 
     id = c.value('./@id', 'int') 
    FROM @locs.nodes('/a/i') T(c) 
) 
SELECT * 
FROM 
    [User] u 
WHERE 
    u.UserID IN (
     SELECT up.UserID 
     FROM UserPreference up JOIN p ON p.id = up.PreferenceID) 
    AND 
    u.UserID IN (
     SELECT ul.UserID 
     FROM UserLocation ul JOIN l ON l.id = ul.LocationID) 

如果WHERE子句看起来太丑陋,你可以删除superflouos用户名参考,并用以下内容替换它:

WHERE 
    u.UserID IN (
     SELECT up.UserID 
     FROM UserPreference up JOIN p ON p.id = up.PreferenceID 
     INTERSECT 
     SELECT ul.UserID 
     FROM UserLocation ul JOIN l ON l.id = ul.LocationID) 

附:我完全失去了对TVF,CSV和其他基于收藏的输入格式的兴趣,目前我只使用XML。