开发者

MySQL call for additional filtering for certain rows, only if another table is populated

Two clarifications:

  • I'm going to actually be doing pagination with this, so ideally it can be one SQL s开发者_开发百科tatement...
  • If this helps, what I'm trying to do is: Get all content for user, BUT if content item has criteria in content_criteria table, check that user also has criteria in users_criteria table, OTHERWISE, content is valid for user

So this might be hard to explain. Let's start with the main tables:

content:

| contentIdNum | contentStr | programIdNum |

A piece of content (unlike users) can only be associated with one program. A typical record would be like this. Both are associated with a program with id of 1.

| 1 | Zelda | 1 |
| 2 | Mario | 1 | 

content_criteria:

| contentIdNum | criteriaIdNum |

A typical record would be like this: (this basically a table that associates content with criteria. Not all content is associated with criteria.)

| 1 | 5 |

** user_criteria: **

| userIdNum | criteriaIdNum |

A typical record would be like this: (this basically a table that associates users with criteria. Not all content is associated with criteria.) Note that userIdNum 1 has the same criteria as contentIdNum 1

| 1 | 5 |

** program_users: **

| userIdNum | criteriaIdNum |

A typical record would be like this (both user 1 and 2 are associated with program 1)

| 1 | 1 |
| 2 | 1 |

So here's what I need to do:

  • Create a MySQL call that returns all pieces of content a user has access to
  • By default, a user has access to all content associated with the programs he is assigned to
  • If a piece of content has criteria associated with it in the content_criteria table, ONLY users with that corresponding criteria in the user_criteria table have access to that content
  • For example, if I pass in userIdNum 1, I should get both pieces of content
  • If I pass in userIdNum of 2, I should only get one piece of content (the one with contentIdNum of 2)

Obviously selecting content that matches a user's programs is easy (below is what I have). I'm trying to figure out an easy way to filter the content - can I do it in one go, or do I have to do a secondary pass and loop through the content via PHP?

SELECT DISTINCT (c.contentIdNum), c.*
FROM content c , program_users pu 
WHERE 1=1 
AND pu.userIdNum = 2 AND pu.programIdNum = c.programIdNum


SELECT  c.*
FROM    content           c , 
        program_users     pu , 
        content_criteria  cc, 
        user_criteria     uc
WHERE   pu.userIdNum      = 2 
AND     pu.programIdNum   = c.programIdNum
and     cc.contentIdNum   = c.contentIdNum
and     uc.criteriaIdNum  = cc.criteriaIdNum
and     uc.userIdNum      = pu.userIdNum

should do the trick.

"distinct" is a really good way of hiding bugs - especially while you're still trying to work out what your query should look like.


Fix it thanks to UNIONs. The first part of the UNION gets all content that does NOT have a criteria to filter by. The second part of the UNION gets all content with a criteria to filter by, if the user has that criteria.

SELECT  c.*
FROM    content           c , 
        program_users     pu 
WHERE   pu.userIdNum      = 1
AND     pu.programIdNum   = c.programIdNum
AND NOT EXISTS (
    SELECT *
    FROM content_criteria cc
    WHERE cc.contentIdNum = c.contentIdNum
)
UNION 
SELECT  c.*
FROM content_criteria cc, users_criteria uc, content c
WHERE cc.contentIdNum = c.contentIdNum
AND cc.criteriaIdNum = uc.criteriaIdNum
AND uc.userIdNum = 1
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜