如何创建 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 过程以根据其他两个表过滤一个表?的主要内容,如果未能解决你的问题,请参考以下文章