2011-02-03 85 views
9

它可能简单,这是我的查询:从SQL查询中删除重复(不只是“用独特的”)

SELECT DISTINCT U.NAME, P.PIC_ID 
FROM USERS U, PICTURES P, POSTINGS P1 
WHERE U.EMAIL_ID = P1.EMAIL_ID AND P1.PIC_ID = P.PIC_ID AND P.CAPTION LIKE '%car%'; 

,但其中一排既有相同u.name,这将只删除重复p.pic_id。我想要它,所以如果有任何重复的名称,它只是遗漏了其他行。这是一个奇怪的查询,但总的来说,我如何将distinct应用于SELECT子句的单个列?

+1

您想要使用单个U.NAME中的多个P.PIC_ID中的哪一个? – 2011-02-03 21:02:46

回答

15

随意选择保持最小PIC_ID。另外,避免使用隐式连接语法。

SELECT U.NAME, MIN(P.PIC_ID) 
    FROM USERS U 
     INNER JOIN POSTINGS P1 
      ON U.EMAIL_ID = P1.EMAIL_ID 
     INNER JOIN PICTURES P 
      ON P1.PIC_ID = P.PIC_ID 
    WHERE P.CAPTION LIKE '%car%' 
    GROUP BY U.NAME; 
1

您需要告诉查询为其他列选择什么值,MINMAX看起来是合适的选择。

SELECT 
    U.NAME, MIN(P.PIC_ID) 
FROM 
    USERS U, 
    PICTURES P, 
    POSTINGS P1 
WHERE 
    U.EMAIL_ID = P1.EMAIL_ID AND 
    P1.PIC_ID = P.PIC_ID AND 
    P.CAPTION LIKE '%car%' 
GROUP BY 
    U.NAME; 
+1

我不认为这是他想要的。我认为他想要所有的照片,但是在一个用户有几张照片的情况下,他不希望用户的名字在列表中重复。 – KeithS 2011-02-03 21:09:12

+1

不要鼓励使用隐含的连接语法。如果你向他展示如何做事,请告诉他如何正确做事。 – HLGEM 2011-02-03 21:10:22

+0

@HLGEM,为了我自己的知识,隐含的语法有什么问题?某些ODBC驱动程序(如tigerlogic的D3)仅支持隐含语法。 – 2011-02-03 21:14:56

0

如果我理解正确的话,你要使用相同的名称(和他们不同的ID),使得他们的名字会出现比表一次的所有照片的列表。我认为这将这样的伎俩:

SELECT U.NAME, P.PIC_ID 
FROM USERS U, PICTURES P, POSTINGS P1 
WHERE U.EMAIL_ID = P1.EMAIL_ID AND P1.PIC_ID = P.PIC_ID AND U.Name IN (
SELECT U.Name 
FROM USERS U, PICTURES P, POSTINGS P1 
WHERE U.EMAIL_ID = P1.EMAIL_ID AND P1.PIC_ID = P.PIC_ID AND P.CAPTION LIKE '%car%'; 
GROUP BY U.Name HAVING COUNT(U.Name) > 1) 

我没有执行,所以有可能是一个语法错误或两个在那里。

1

如果我理解正确的话,你要列出排除在只有一列重复,内连接到一个子选择

select u.* [whatever joined values] 
from users u 
inner join 
(select name from users group by name having count(*)=1) uniquenames 
on uniquenames.name = u.name 
2

你的问题是怎么样的混乱;你想每个用户只显示一行,还是你想要显示每张图片的一行,但是抑制U.NAME字段中的重复值?我想你想要第二个;如果不是,第一个就有很多答案。

是否显示重复值是显示逻辑,SQL并非真正为此设计的。您可以在循环中使用游标来逐行处理结果,但是会失去很多性能。如果你有一种像.NET语言或者Java这样的“智能”前端语言,那么无论你把这些数据放到什么样的构造中,都可以很便宜地操作,以便在最终显示UI之前抑制重复的值。

如果您使用的是Microsoft SQL Server,并且要在数据层完成变换HAS,则可以考虑使用CTE(计算表表达式)来保存初始查询,然后从每行中选择值CTE根据前一行中的列是否保存相同的数据。它会比光标更高效,但是它会有点麻烦。观察:

USING CTE (Row, Name, PicID) 
AS 
(
    SELECT ROW_NUMBER() OVER (ORDER BY U.NAME, P.PIC_ID), 
     U.NAME, P.PIC_ID 
    FROM USERS U 
     INNER JOIN POSTINGS P1 
      ON U.EMAIL_ID = P1.EMAIL_ID 
     INNER JOIN PICTURES P 
      ON P1.PIC_ID = P.PIC_ID 
    WHERE P.CAPTION LIKE '%car%' 
    ORDER BY U.NAME, P.PIC_ID 
) 
SELECT 
    CASE WHEN current.Name == previous.Name THEN '' ELSE current.Name END, 
    current.PicID 
FROM CTE current 
LEFT OUTER JOIN CTE previous 
    ON current.Row = previous.Row + 1 
ORDER BY current.Row 

以上示例是TSQL特定的;不保证能够像PL/SQL那样在任何其他DBPL中工作,但我认为大多数企业级SQL引擎都有类似的东西。