在sql中使用LIKE和IN与子查询[重复]

Posted

技术标签:

【中文标题】在sql中使用LIKE和IN与子查询[重复]【英文标题】:use LIKE and IN with subquery in sql [duplicate] 【发布时间】:2021-04-26 18:43:34 【问题描述】:

我正在使用 Oracle SQL,我有以下表格:

用户

UserID     |  UserPeers   |  Gender
-----------+--------------+--------
Mike       |  Tom1, Bob1  |  M
John       |  Tom1, Greg1 |  M
Sally      |Mike1, John1  |  F
Sara       | Sally1, Bob1 |  F

special_user

UserID     
-------
Tom1       
John1      

我正在尝试获取在 special_users 表中存在同级的所有用户。

我的尝试:

SELECT * 
FROM user 
WHERE '%' UserPeers '%' LIKE IN (SELECT UserID FROM special_users)

显然语法是错误的,所以我不知道该怎么做?

预期结果:

UserID     | UserPeers    | Gender
-----------+--------------+---------
Mike       | Tom1, Bob1   |  M
John       | Tom1, Greg1  |  M
Sally      | Mike1, John1 |  F

【问题讨论】:

修复你的数据模型,这样你就不会在一个字符串中存储多个值。 @GordonLinoff 同意你的观点,但我不拥有它。 您不必对用户使用诸​​如“第三范式”之类的学术术语。您所要做的就是与他们讨论索引以及更好的模型如何使编码更容易。但是,如果您想成为一名学者,那么我可以建议this 吗? 【参考方案1】:

您可以将要匹配的字符串和包含要匹配的userid 的字符串包装在, 分隔符中,以确保匹配完整的userid(而不是天真地使用LIKE不考虑周围的分隔符,只匹配部分userid)。像这样:

SELECT *
FROM   "USER" u
WHERE  EXISTS (
  SELECT 1
  FROM   special_user su
  WHERE  ', ' || u.userpeers || ', ' LIKE '%, ' || su.userId || ', %'
)

其中,对于样本数据:

CREATE TABLE "USER" ( UserID, UserPeers, Gender ) AS
SELECT 'Mike',  'Tom1, Bob1',   'M' FROM DUAL UNION ALL
SELECT 'John',  'Tom1, Greg1',  'M' FROM DUAL UNION ALL
SELECT 'Sally', 'Mike1, John1', 'F' FROM DUAL UNION ALL
SELECT 'Sara',  'Sally1, Bob1, TimTom1', 'F' FROM DUAL;

CREATE TABLE special_user ( UserID ) AS
SELECT 'Tom1' FROM DUAL UNION ALL
SELECT 'John1' FROM DUAL;

注意:我更改了 Sally 以添加一个对等点 TimTom1,即使包含 Tom1 子字符串也不应该匹配。

哪些输出:

USERID USERPEERS GENDER
Mike Tom1, Bob1 M
John Tom1, Greg1 M
Sally Mike1, John1 F

db小提琴here

【讨论】:

【参考方案2】:

您可以使用这样的查询:

SELECT DISTINCT u.*
FROM "User" u
INNER JOIN special_user su ON u.UserPeers like '%' || su.UserID || '%';

它在 User 行和 special_user 行之间进行 JOIN,并在 UserPeers 中包含 UserID 时匹配。

我添加了 DISTINCT 子句来过滤重复行(以防两个 special_user 在 UserPeers 行中)。

【讨论】:

如果userid 作为另一个userpeers 的子字符串存在,这将返回太多行。 db<>fiddle 这将返回 'ORA-00942: table or view does not exist' 除非该表是使用区分大小写的密码创建的,如 ;CREATE TABLE "User" .....',即不是默认值,因此在统计上不太可能。 @EdStevens 我没有选择表名,我使用了问题中的名称。 @nachospiu - 明白。但是您绝对可以使用混合大小写的名称而不受惩罚,只要从不(包括在创建时)用双引号将其括起来。人们使用这种结构很常见:'CREATE TABLE User 。 . 。 (注意没有双引号)。但是如果没有双引号,它仍然在数据字典中以大写形式创建。但只要所有未来的引用也没有双引号,你就可以有效地使用不区分大小写的用法。因此,应指出并限定示例中双引号的使用。 @EdStevens 在 Oracle 中,USER (user, User, userR) 是保留字,因此必须使用双引号将其用作表名(双引号允许区分大小写的名称)。如果我在查询中使用“用户”,很明显我创建了带有双引号的表。在表描述(问题中)中,表名是用户(不是用户),那么我为什么要更改它呢?如果您在查询中忘记了表名周围的双引号,这没什么大不了的,查询将失败,您可以添加它们。我认为任何使用 Oracle 的人都知道这一点。我不喜欢在名称中使用双引号,但很多时候我不得不使用它们。【参考方案3】:

将其包装在子查询中。下面几乎是ANSI代码。 ||是在oracle中连接字符串。

SELECT *
FROM UserList
WHERE EXISTS (
    SELECT *
    FROM special_user
    WHERE UserList.UserPeers LIKE '%' || UserID || '%'
);

http://sqlfiddle.com/#!4/f6e680/18

【讨论】:

如果userid 作为另一个userpeers sqlfiddle 的子字符串存在,这将返回太多行。【参考方案4】:

一种选择是将UserPeers 列的逗号分隔值与分层查询分开,以便在表之间按名称进行比较,例如

SELECT uu.UserID,UserPeers,Gender
  FROM
  (
   SELECT u.*, TRIM(REGEXP_SUBSTR(UserPeers,'[^,]+',1,level)) AS name_piece
     FROM "user" u
  CONNECT BY level <= REGEXP_COUNT(UserPeers,',') + 1
      AND PRIOR SYS_GUID() IS NOT NULL   
      AND PRIOR u.UserID = u.UserID ) uu
  JOIN special_user su
    ON name_piece = su.UserID    

Demo

【讨论】:

以上是关于在sql中使用LIKE和IN与子查询[重复]的主要内容,如果未能解决你的问题,请参考以下文章

在 SQL 语句中将“IN”与子查询一起使用

SQL查询中in和exists的区别分析

SQL中 exists和in的区别是啥啊?

sql 包含于语法

SQL关于IN和EXISTS的用法和区别的比较

结合 SQL Server 的“LIKE”和“IN”[重复]