使用EXISTS和IN指令获取重复记录的Oracle语法SELECT。

3
我在苦苦挣扎地编写 SQL 查询语句,它应该基于这样的表结构:
PID (type VARCHAR)    ATTR (type VARCHAR)
U1                    attribute1
U1                    locale
U2                    attribute1
U2                    locale
U3                    attribute1
U3                    attribute2

我想做的是选择所有不包含“locale”字符串的记录的PID,并且这些记录在ATTR列中不存在,因此在我展示的示例中,该查询应返回“U3”。
我尝试过类似以下的查询:
SELECT DISTINCT PID p
FROM tablename
WHERE NOT EXISTS (SELECT * FROM table
                  WHERE PID = 'p' AND ATTR NOT IN 'locale');

类似的东西,但我要么没有正确理解SQL语法,要么在犯一些其他错误——我没有得到正确的结果。

有人知道可能出了什么问题吗?

P.S. 由于我得到的反馈,我必须做错了什么,请允许我补充一些信息,也许这会有所帮助。

我谈论的表是一个SAP J2EE堆栈标准表(UME_STRINGS),包含用户数据(SAP术语中的UME——用户管理引擎)。除了PID和ATTR之外,它还包含许多其他字段,我没有考虑它们,因为它们似乎不重要。

然而,我需要找到所有没有设置区域设置的用户帐户。由于用户管理显然是“懒惰”的,因此只有在设置区域设置时才会创建这样的记录(具有任意PID和值“locale”在ATTR中的记录)。这实际上意味着表中存在许多用户的任意记录(相同的PID值),但是这些记录中没有一个在ATTR字段中有一个值'locale'。因此,算法可以是:

1.)将表聚类到相同的PID上

2.)在每个群集内迭代并检查是否在此群集内没有具有'locale'在ATTR字段中的记录,如果是,则将此PID添加到输出

3.)返回找到的PID列表

所有这些都最好用单个SQL查询完成。

可用的JAVA API(com.sap.security.api.IUserSearchFilter)不允许您设置空值进行搜索,因此我别无选择,只能直接询问DB。

除了“locale”记录之外,当然还有许多其他记录,因为每个用户、组、角色等的每个属性都是以这种方式建模的——像U1 - attribute1之类的东西。

所以我需要一个查询,给我没有像“PID - 'locale' in ATTR”的条目的PID的用户。

如果我的描述令人困惑或不完整,请问。再次感谢

P.P.S. 添加了一些带有示例数据和表结构的屏幕截图

table structure

sample data

could PID be null?


PID 可以为 null 吗?(您可以在实际数据中检查:select count(PID) where PID is null)。 - user5683823
不,由于ER的存在,它始终有一个值设置。 - John Doe
5个回答

3

无需使用EXISTS()IN(),您可以仅使用HAVING子句和CASE表达式

SELECT t.pid
FROM YourTable t
GROUP BY t.pid
HAVING COUNT(CASE WHEN t.attr = 'locale' THEN 1 END) = 0

谢谢,听起来没错,但实际上提供了太多的数据,还有U1和U2。事实上只有U3应该出现。也许我做错了什么或者忘记提到什么了? - John Doe
@JohnDoe - 这个答案是正确的(其他几个答案也是正确的),所以你一定是做错了什么。请分享一些数据,让我们知道你认为这个查询产生了错误的结果。 - user5683823
我和mathguy有同样的感觉,我只是提取了问题的一部分,以保持简单。似乎这不是一个好主意,我编辑了整个帖子并添加了一些信息,也许会有所帮助。 - John Doe

0

你可以使用 NOT IN 和子查询

SELECT DISTINCT PID 
FROM tablename
WHERE PID NOT IN (SELECT PID FROM table
                      WHERE  ATTR =  'locale');

最终尝试 TRIM(BOTH FROM ATTR)
SELECT DISTINCT PID 
FROM tablename
WHERE PID NOT IN (SELECT PID FROM table
                      WHERE LOWER(TRIM(BOTH  FROM ATTR))=  'locale');

抱歉,scaisEdge,返回“未选择任何行”。 - John Doe
@mathguy 正确的,我的回答只涉及到OP所提供的数据样本。 - ScaisEdge
PID 不能为空,而且更改的查询返回了太多的数据。看起来它还包括 U1 和 U2 数据,我假设除了 U1 - locale、U2 - locale 等之外的任何内容。我需要的是单个 PID 值,它在与 PID - locale 相同的表中没有记录。 - John Doe
@JohnDoe - 我能想到的唯一可能是你数据中的 'locale' 可能包含了你看不到的空格,或者大小写不同('locale' 不等同于 'Locale' 或 'LOCALE'!) - user5683823
嗯,显然它也返回了带有ATTR <> 'locale'的PID记录,即使对于具有这样的“locale”条目的PID,我并不想要这个。这可能是问题所在? - John Doe
显示剩余4条评论

0

你可以做到这个

SELECT DISTINCT PID
FROM tableName
WHERE PID NOT IN (SELECT PID FROM tableName WHERE Attr = 'locale')

谢谢,但提供了太多数据,类似于 sagi 的回答。我期望只得到那些没有任意 PID 和“locale”值的 ATTR 记录的值。在我的例子中,这将是 U3。 - John Doe
以上查询仅返回U3,因为U2和U1具有Attr值为locale的行。 - Mudassir Hasan
不用了,谢谢。我在我的机器上运行查询(Oracle 11g,Win 2008 R2服务器),我觉得我的情况可能不完整。我在整个帖子中添加了一些信息,如果您有遗漏的内容,请随时询问。 - John Doe
@JohnDoe 请再次编辑您的帖子,并添加您正在运行但无法正常工作的查询。 - sagi
Sagi,这很简单 - 推荐的查询都没有起作用 :) 我假设这是第8层问题,但我无法弄清楚我做错了什么。我已经完成了整个问题描述,它非常直接和准确,如果你缺少什么 - 让我知道,谢谢。 - John Doe

0
SELECT DISTINCT PID p
FROM tablename t
WHERE NOT EXISTS (SELECT * FROM tablename t2
                  WHERE t2.PID = t.PID AND t2.ATTR = 'locale');

谢谢,但是返回“没有选择行”。 - John Doe
应该是 ... WHERE NOT EXISTS (SELECT * FROM tablename t2 WHERE t2.PID = t.PID AND t2.ATTR = 'locale'); - joop
谢谢,但与其他答案类似,它提供了太多的数据 - 显然也包括像U1-attribute1这样的记录,我们不想这样做。 - John Doe

0
尝试这个。问题在于一些其他查询中的不存在仅查找属性locale,而没有通过PID进行连接。
select t1.pid from tablename t1
where not exists 
(select t2.pid from tablename t2 where t2.pid=t1.pid and    t2.attr='locale');

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接