如何创建 MsSQL 过程以根据其他两个表过滤一个表?

Posted

技术标签:

【中文标题】如何创建 MsSQL 过程以根据其他两个表过滤一个表?【英文标题】:How can I create MsSQL procedure for filtering one table based on two others? 【发布时间】:2021-10-08 13:05:13 【问题描述】:

我想在 Microsoft SQL Server 中创建过程。 我有以下表格

用户 - 用户 ID (PK)、名字、姓氏... 技能 - SkillId (PK),名称 UserSkill - UserSkillId (PK)、UserId (FK)、NameId (FK) 职业 - ProfessionId (PK),姓名 UserProfession - UserProfessionId (PK)、UserId (FK)、ProfessionId (FK) 兴趣 - InterestId (PK)、名称 UserInterest - UserInterestId (PK)、UserId (FK)、InterestId (FK)

我想创建将接收技能、兴趣和职业的 ID 作为参数的存储过程,并且该过程应该返回包含作为参数传递的所有技能、兴趣和职业的所有用户。有什么想法我该怎么做?

【问题讨论】:

我认为这是针对 Microsoft SQL Server 的,但您没有指定。请准确确认这是针对哪个平台; mysql、Oracle、SQL Server 等 对 DBMS 中可用的参数使用 UDT、JSON、数组。 【参考方案1】:

假设 SQL Server...

表格模型:

CREATE TABLE app_user (
  id    INT,
  name  NVARCHAR(32)
);
INSERT INTO app_user VALUES (1, 'User_One'), (2, 'User_Two');

CREATE TABLE skill (
  id    INT,
  name  NVARCHAR(32)
);
INSERT INTO skill VALUES (1, 'Skill_One'), (2, 'Skill_Two'), (3, 'Skill_Three');

CREATE TABLE profession (
  id    INT,
  name  NVARCHAR(32)
);
INSERT INTO profession VALUES (1, 'Prof_One'), (2, 'Prof_Two'), (3, 'Prof_Three');

CREATE TABLE interest (
  id    INT,
  name  NVARCHAR(32)
);
INSERT INTO interest VALUES (1, 'Int_One'), (2, 'Int_Two'), (3, 'Int_Three');

CREATE TABLE user_skill (
  user_id   INT,
  skill_id  INT
)
INSERT INTO user_skill VALUES (1, 1), (1, 2), (1, 3), (2, 2), (2, 3);

CREATE TABLE user_profession (
  user_id        INT,
  profession_id  INT
)
INSERT INTO user_profession VALUES (1, 1), (1, 2), (1, 3), (2, 2), (2, 3);

CREATE TABLE user_interest (
  user_id      INT,
  interest_id  INT
)
INSERT INTO user_interest VALUES (1, 1), (1, 2), (1, 3), (2, 2), (2, 3);

参数的数据类型和存储过程:

CREATE TYPE identifier_list AS TABLE ( id INT );

CREATE PROCEDURE get_users
  @skill_id_list        identifier_list READONLY,
  @profession_id_list   identifier_list READONLY,
  @interest_id_list     identifier_list READONLY
AS
  WITH
    user_by_skill
  AS
  (
    SELECT user_id
      FROM user_skill
INNER JOIN @skill_id_list  filter
        ON filter.id = user_skill.skill_id
  GROUP BY user_id
    HAVING COUNT(*) = (SELECT COUNT(*) FROM @skill_id_list)
  ),
    user_by_profession
  AS
  (
    SELECT user_id
      FROM user_profession
INNER JOIN @profession_id_list  filter
        ON filter.id = user_profession.profession_id
  GROUP BY user_id
    HAVING COUNT(*) = (SELECT COUNT(*) FROM @profession_id_list)
  ),
    user_by_interest
  AS
  (
    SELECT user_id
      FROM user_interest
INNER JOIN @interest_id_list  filter
        ON filter.id = user_interest.interest_id
  GROUP BY user_id
    HAVING COUNT(*) = (SELECT COUNT(*) FROM @interest_id_list)
  )
  SELECT
    app_user.*
  FROM
    app_user
  INNER JOIN
    user_by_skill
      ON user_by_skill.user_id = app_user.id
  INNER JOIN
    user_by_profession
      ON user_by_profession.user_id = app_user.id
  INNER JOIN
    user_by_interest
      ON user_by_interest.user_id = app_user.id
  ;

示例用例:

DECLARE @skills identifier_list;
INSERT @skills VALUES (1), (2);

DECLARE @interests identifier_list;
INSERT @interests VALUES (2), (3);

DECLARE @professions identifier_list;
INSERT @professions VALUES (1), (3);

EXEC get_users @skills, @professions, @interests

演示:https://dbfiddle.uk/?rdbms=sqlserver_2019&fiddle=1970babe4ebb70c1e402f9ebfae03fd7

【讨论】:

或者,使用INTERSECT:dbfiddle.uk/… 我现在只有一个问题。例如,如果我没有通过任何技能,程序将不会返回任何用户。它应该工作的方式是,如果我没有通过任何技能,程序不应该按技能过滤用户。 @amircokoja - 没有时间考虑,您可以直接使用LEFT JOIN,然后将COUNT(*) 替换为COUNT(filter.id)...dbfiddle.uk/… @amircokoja - 或者,也许... dbfiddle.uk/…

以上是关于如何创建 MsSQL 过程以根据其他两个表过滤一个表?的主要内容,如果未能解决你的问题,请参考以下文章

Qlikview:如何创建汇总表以过滤多个关联表

拆分 XMLTYPE 以根据条件创建两个 XMLTYPE

MS SQL:每 15 分钟将数据流过滤到第一个值

使用全文搜索和其他条件搜索1300万条记录

如何让mssql 某个表 重置表ID? 或者从某个数字开始。。。

如何根据键进行过滤以选择两个值中的任何一个