简体   繁体   中英

SQL Server + Selecting records with sub tables items

I have a post table which has a photo sub table, so one post can have many photos, one of the photo table column is [Priority].

I need to select records from the post table with only the photo that has a top priority in another table:

So the result should be like:

Photo  Post
pic1   Article1
picX   Article2

Currently my results shows as

Photo  Post
pic1   Article1
pic2   Article1
picX   Article2

with this query:

 SELECT  [Photo], 
         [PostTitle]
 FROM [Post] sp
 INNER JOIN [PostPhotos] spp
 ON (sp.AutoId = spp.PostId)
 WHERE sp.[AutoId] IN (SELECT [PostID] 
                       FROM [Favorites] 
                       WHERE [UserId] = 'UserXXX')

I tried a join query without success:

 SELECT photo, 
        [PostTitle],
        [AskingPrice]
 FROM (SELECT sp.[AutoId], 
              [PostTitle] 
       FROM [SellPost] sp
       WHERE sp.[AutoId] IN (SELECT [PostID] 
                             FROM [Favorites] 
                             WHERE [UserId] = 'UserId') )a
 full OUTER JOIN(SELECT TOP 1 [PostId], 
                        [photo] 
                 FROM [PostPhotos] spp 
                 WHERE PostId IN (SELECT [PostID] 
                                  FROM [Favorites] 
                                  WHERE [UserId] = 'UserXXX') 
                 ORDER BY [Priority] ASC )b
  on (a.AutoId = b.PostId)
  order by a.AutoId; 

My Tables:

Table Post
PostId, PostTitle

Table PostPhotos
AutoId, PostId, Photo, Priority --> 1 post can have many photos

Can someone please kindly assist. Thanks.

Try with this hint:

SELECT [p].[PostId],[PostTitle],[Photo] FROM [Post] p
INNER JOIN [PostPhots] pp
ON [p].[PostId] = [pp].[PostId] 
WHERE [p].[PostId] 
IN (SELECT TOP 1 [PostId] FROM [PostPhotos] ORDER BY [Priority] DESC)

A few things are unclear from your description (like what is AutoId , what is the primary key of PostPhotos and what are you doing with Favorites /what does that table look like). But here is the general idea:

WITH RankedPhotos AS (
  SELECT
    PostId,
    AutoId, -- I'm assuming this is the primary key of PostPhotos?
    RANK() OVER (PARTITION BY AutoId, PostId ORDER BY Priority ASC) AS PhotoRank
  FROM
    Post p JOIN
    PostPhotos pp ON
      p.PostId = pp.PostId
), TopPhotos AS (
  SELECT
    PostId,
    AutoId
  FROM
    RankedPhotos
  WHERE
    PhotoRank = 1
)
SELECT
  PostTitle,
  Photo
FROM
  RankedPhotos r JOIN
  Post p ON
    r.PostId = p.PostId JOIN
  PostPhotos pp ON
    r.AutoId = p.AutoId

Of course you could unwrap the CTE and use nested subqueries (you could also probably get rid of TopPhotos completely), but this is probably easier to see/understand.

The basic idea is:

  • In RankedPhotos , "rank" all of the Post / PostPhoto pairs
  • In TopPhotos filter the IDs down to the ones with the highest ranks
  • Join back to the original tables to get the records you actually want

Obviously if you need to filter by some other criteria (like a user) that will need to be added. It's best to add that as early in the process as possible (ie in RankedPhotos ) since otherwise the database may end up doing more work than it needs.

Sub queries not my strongest point but I think the below may work:

SELECT t1.Photo, t2.PostTitle
FROM Post t2
   INNER JOIN PostPhotos t1 ON (t2.PostID = t1.PostID)
WHERE t1.AutoID IN (SELECT TOP 1 d.AutoID, d.PostID
                        FROM PostPhotos As d
                        WHERE d.PostID = t1.PostID 
                        ORDER BY d.Priority, d.AutoID)

Note the addition of d.AutoID in the ordering of the subquery, this is in case two photos have the same priority.

EDIT I learnt a lot of what I know about subqueries here

Sorry for the mistakes in my post, I think I have been thinking too deep, all I need was:

   SELECT [p].[AutoId], [PostTitle], [Photo] FROM [Post] p
      INNER JOIN [PostPhotos] pp
      ON [p].[AutoId] = [pp].[PostId] 
      WHERE p.[AutoId] IN (SELECT [PostID] FROM [Favorites] WHERE [UserId] = @UserId)
      AND [Priority] = 1
SELECT  B.Photo,A.[PostTitle]
FROM    [Post]  A   INNER JOIN
        (SELECT AutoId,PostId,Photo,Priority
        FROM    PostPhotos
        WHERE   Priority =1) B ON A.[PostId] = B.[PostId]

I would do it in this way, and both of inner join and left join can get the result you want.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM