首页 > 解决方案 > 提供要从 mysql 结果中排除的用户主机对

问题描述

要处理的数据:

+-------------+-------------+
| user        | host        |
+-------------+-------------+
| user1       | host1       | -
| user1       | ip1         | -
| user1       | host2       | *
| user2       | host2       | -
| user2       | ip2         | -
| unknown     | unknown     | +
| user1       | unknown     | +
| unknown     | host        | +
+-------------+-------------+

表格右侧的符号是: - 不显示 | + 显示未知 | * 因为一个用户只能连接到一个主机,除非我已经授权它,在这种情况下,我也会将用户主机对提供给调用,它不会显示。

无论如何,这就是我希望事情发生的方式。

这就是我在问题的帮助下所处的位置,因为现在有一个进一步的条件需要提出一个新问题。

目前的程序

USE mysql;
DROP PROCEDURE IF EXISTS ShowUsers;
DELIMITER $

CREATE PROCEDURE `ShowUsers`(
  IN KnownUsers varchar(500),
  IN KnownHosts varchar(500)
)
BEGIN
  SELECT
    user,host
  FROM
    user
  WHERE 
    NOT FIND_IN_SET(host, KnownHosts)
  AND
    NOT FIND_IN_SET(user, KnownUsers)
  ORDER BY user, host ASC;
END $
DELIMITER ;

像这样调用程序

# known users and known hostnames or ips to match and exclude from results.
SET @Usernames = 'user1,user2';
SET @Hostnames = 'host1,host2,ip1,ip2'

CALL ShowUsers(@Usernames, @Hostnames);

预期结果:

+-------------+-------------+
| user        | host        |
+-------------+-------------+
| user1       | host2       | *
| unknown     | unknown     | +
| user1       | unknown     | +
| unknown     | host        | +
+-------------+-------------+

我希望能够提供多个用户:主机对(已知合法凭据)并返回不匹配的结果,因此在查询结果中仅返回可疑/非法凭据。

我创建了一个小提琴https://www.db-fiddle.com/f/xb7dWXbkokHGbcPdzR7BUa/4希望你能看到我的目标。

标签: mysqlstored-proceduresmariadb

解决方案


根据我从您的问题陈述中可以理解的任何内容,您将需要使用多个字符串操作来满足您的条件(下面的内联注释中的解释):

询问

SELECT
  `user`,`host`
FROM
  tbl
WHERE 

 -- NOT condition to avoid returning one-to-one mapping between `user` and `host`
 -- If `user` exist in the @Usernames, and the position of the 
 -- `user` matches with the position of the `host` in the @Hostnames
 NOT ( 
       FIND_IN_SET(`user`, @Usernames) > 0
       -- Host and User are at same position in the lists
       AND FIND_IN_SET(`user`, @Usernames) = FIND_IN_SET(`host`, @Hostnames) 
     )

 AND 

 -- NOT condition to handle `host` at the end of @Hostnames list, where 
 -- there is no corresponding `user` mapped
 NOT ( 
      FIND_IN_SET(`host`, @Hostnames) > CHAR_LENGTH(@Usernames) 
                                        - CHAR_LENGTH(REPLACE(@Usernames, ',', '')) 
                                        + 1 
     );

结果

| user    | host    |
| ------- | ------- |
| user1   | host2   |
| unknown | unknown |
| user1   | unknown |
| unknown | host    |

在 DB Fiddle 上查看

警告:当列表中没有用户时,上述查询将不起作用@Usernames。为简洁起见,我避免让条件变得更复杂来处理它。此外,我怀疑在您的实际用例中,您会遇到列表中没有用户的情况。


推荐阅读