选择基于多对多的过滤器

时间:2013-10-28 17:52:04

标签: sql sql-server

晚上好,

我有一个类似于下图的表格布局。 用户表格存储了我的大部分信息。对于每个用户,我还可以选择未确定数量的偏好位置,我将其存储在联结表中,如图所示。

Data table layout

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

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

  3. 这就是我为单个UserID ...

    返回分隔首选项逗号分隔的内容
    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 个答案:

答案 0 :(得分: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')

答案 1 :(得分: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 UserID引用并将其替换为以下内容:

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)

P.S。我对TVF,CSV和其他基于集合的输入格式完全失去了兴趣,目前我只使用XML。