加入操作重复

时间:2011-04-17 14:42:00

标签: mysql sql database join

假设我们有两个表:Users(UserId,UserName,UserPhoto)和Articles(ArticleId,UserId,ArticleText)。现在我们执行内部联接查询以检索带有文章的用户:

SELECT UserId, UserName, UserPhoto, ArticleId, ArticleText 
FROM Users as u INNER JOIN Articles as a ON u.UserId = a.UserId

查询结果的结构如下:

UserId1 UserName1 UserPhoto1 ArticleId1 ArticleText1
UserId1 UserName1 UserPhoto1 ArticleId2 ArticleText2

因此,对于第一个用户,我们有两篇文章,UserName1和UserPhoto1是重复的。如果UserPhoto存储几千兆字节的blob怎么办?

我希望数据库协议对这种情况有一些优化(可能是某些映射告诉UserPhoto对于第一行和第二行是相同的)但我从未遇到任何关于此的注释。所以我只想确保存在这种优化,我不需要自己解决它

4 个答案:

答案 0 :(得分:2)

首先,为Photos创建第三个表,并将UserId与Photo关联。其次,您需要运行两个单独的查询才能检索:

  1. 用户提交的每张照片
  2. 与特定用户/照片相关联的每篇文章
  3. 您将遍历所有用户/照片对,并查询循环内的文章。

答案 1 :(得分:2)

您可以运行两个查询,一个用于获取用户数据(因此每张照片将传输一次):

SELECT u.UserId
     , u.UserName
     , u.UserPhoto
FROM Users as u

和另一个得到其余的(文章)数据:

SELECT a.UserId               <--- only UserId this time
     , a.ArticleId
     , a.ArticleText 
FROM Users as u
  INNER JOIN Articles as a
    ON u.UserId = a.UserId

最后,使用用户ID将结果合并到应用程序代码中。

答案 2 :(得分:2)

您可以避免多次获取照片:

SELECT * FROM (
  SELECT UserId, UserName, UserPhoto, ArticleId, ArticleText 
    FROM Users as u INNER JOIN Articles as a ON u.UserId = a.UserId
    WHERE ArticleId IN (SELECT MIN(ArticleId) FROM Articles GROUP BY UserId)
  UNION ALL
  SELECT UserId, UserName, NULL, ArticleId, ArticleText
  FROM Users as u INNER JOIN Articles as a ON u.UserId = a.UserId
  WHERE ArticleId NOT IN (SELECT MIN(ArticleId) FROM Articles GROUP BY UserId)
) base
ORDER BY ArticleId;  // UserId,ArticleId will also work if you want it sorted by users.

这仅在获取第一篇文章的情况下获取照片,并为后续文章返回NULL。您的应用程序可以在首次阅读时缓存照片。

答案 3 :(得分:1)

1)无论photoblob在结果集中出现多少次,它都会被读取(从服务器中的磁盘到内存),内置优化以确保发生这种情况。

2)然而,它可以多次传输(从服务器到客户端),没有内置的优化。

3)最好的解决方案是将此包装为一个返回2个记录集的存储过程,并在clinet代码中进行连接,这种方法不同于运行需要两次往返的2个查询。

4)如果您不想这样做,您可以以CSV格式获取用户的所有文章ID,然后您可以轻松地将csv拆分为客户端代码中的单独字符串。

以下是示例输出

UserId  UserName  UserPhoto   CSV_ArticleId               CSV_ArticleText
------- --------- ----------  ------------------------    ----------------------------
UserId1 UserName1 UserPhoto1  ",ArticleId1,ArticleId2"    ",ArticleText1,ArticleText2"
UserId2 UserName2 UserPhoto2  ",ArticleId3"               ",ArticleText3"

这是你如何做到的。在测试数据库上逐字运行代码,您可以看到结果

CREATE TABLE Users(UserId int , UserName nvarchar(256), UserPhoto nvarchar(256))

CREATE TABLE Articles (ArticleId int , UserId int , ArticleText nvarchar(256))

INSERT INTO Users(UserId,UserName,UserPhoto)
VALUES (2,'2a','2pa')
INSERT INTO Users(UserId,UserName,UserPhoto)
VALUES (1,'a','pa')

INSERt INTO Articles (ArticleId, UserId, ArticleText)
VALUES (2,2,'text2')
INSERt INTO Articles (ArticleId, UserId, ArticleText)
VALUES (1,2,'text1')

;WITH tArticles AS (SELECT ArticleId, UserId, ArticleText FROM Articles)
SELECT 
    UserId, 
    UserName, 
    UserPhoto,
    (SELECT TOP 1 LTRIM(
                        (SELECT ',' + CONVERT(nvarchar(256),A.ArticleId) FROM Articles A WHERE U.UserId = A.UserId ORDER BY A.ArticleId FOR XML PATH(''))
                        )) as CSV_ArticleId,
    (SELECT TOP 1 LTRIM(
                        (SELECT ',' + CONVERT(nvarchar(256),A.ArticleText) FROM Articles A WHERE U.UserId = A.UserId ORDER BY A.ArticleId FOR XML PATH(''))
                        )) as CSV_ArticleText                   

FROM Users U