sql 查询的正确语法和 WHERE EXISTS 替代方案

Posted

技术标签:

【中文标题】sql 查询的正确语法和 WHERE EXISTS 替代方案【英文标题】:correct syntax for sql query and a WHERE EXISTS alternative 【发布时间】:2013-05-30 11:18:36 【问题描述】:

我想编写以下查询,以便从工作表中返回所有工作,其中专业和子专业对等于某个用户的专业和子专业对之一(4 对之一)。如果用户有一对 subprofession=0,这意味着获取相应专业的所有子专业:

类似这样的:

select * from jobs j
where 
      (j.profession, j.subprofession) in 

      (select (u.profession1, u.subprofession1) from users u where userid=@userid),
       select (u.profession2, u.subprofession2) from users u where userid=@userid),
       select (u.profession3, u.subprofession3) from users u where userid=@userid),
       select (u.profession4, u.subprofession4) from users u where userid=@userid)
and
j.profession in (select u.profession1, u.profession2, u.profession3, u.profession4 from users u where userid=@userid) and (u.subprofession1 = 0 or u.subprofession2 = 0 or u.subprofession3 = 0 or u.subprofession4 = 0))

我知道这个查询在语法上是错误的并且没有做它应该做的事情,那么使用 IN 子句或 WHERE EXISTS 实现上述目的的方法是什么?

jobs: profession, subprofession 
1      (100,        200)
2      (100,        300)
3      (100,        400)
4      (100,        500)
5      (200,        300)
6      (400,        500)
7      (400,        100)
8      (400,        600)
9      (200,        200)
10     (600,        700)
11     (100,        100)
12     (500,        300)
13     (200,        200)

users: (prof1, subprof1, prof2, subprof2, prof3, subprof3, prof4, subprof4)
1       (100,   100,      757,   646,      100,   0,        500,   400)
2       (100,   2,        565,   76,       567,   534,      433,   565)
3       (200,   454,      553,   345,      354,   435,      334,   877)
4       (500,   300,      456,   565,      354,   435,      545,   435)
5       (400,   453,      434,   453,      423,   234,      324,   4435)
6       (100,   400,      435,   543,      465,   654,      454,   543)
7       (435,   435,      600,   700,      100,   0,        500,   400)
8       (100,   100,      553,   345,      100,   0,        500,   400)

请求的查询将从作业表行返回: 1,2,3,4,11

这些是职业和子职业的值(作为一对)出现在用户 prof 和 subprof 对之一中的行。另外,因为用户 1 有一个条目(prof3=100 和 subprof3=0),所以查询应该返回 proession 为 100 的所有订单(对于所有子专业)。

【问题讨论】:

SQL 只是 结构化查询语言 - 许多数据库系统使用的语言,但不是数据库产品...很多事情都是特定于供应商的 - 所以我们真的需要知道您正在使用什么数据库系统(以及哪个版本)(请相应地更新标签)...... 如果有一些示例表和查询的预期结果也会很有用 这个不清楚:if the user has a pair where the subprofession=0, that means take all the subprofessions for the respective profession 你对数据库设计有什么影响吗?您可以将用户和专业/子专业之间的关系移动到关系表(用户-专业、用户-子专业、专业-子专业)。 @Tim如果用户没有指定子专业(想想专业化),那么就获得该专业的所有工作。否则,我猜只是那些与子专业匹配的人。 OK:这个理解是否正确:如果我们在pair1中有(100,100)和pair3中有(100,0),我们不应该消除需要子专业100的职业100中的工作,因为pair3中的0是一个“通配符”,意思是“指定职业中的任何工作”;在这种情况下,pair3 会覆盖 pair1。 【参考方案1】:

这应该适合你:

SELECT  *
FROM    Jobs
WHERE   EXISTS
        (   SELECT  1
            FROM    Users
            WHERE   Users.UserID = @UserID
            AND (   (Users.Profession1 = Jobs.Profession AND Users.SubProfession1 IN (Jobs.SubProfession, 0))
                OR  (Users.Profession2 = Jobs.Profession AND Users.SubProfession2 IN (Jobs.SubProfession, 0))
                OR  (Users.Profession3 = Jobs.Profession AND Users.SubProfession3 IN (Jobs.SubProfession, 0))
                OR  (Users.Profession4 = Jobs.Profession AND Users.SubProfession4 IN (Jobs.SubProfession, 0))
                )
        );

Example on SQL Fiddle

编辑

由于是SQL-Server,可以使用CROSS APPLY..VALUES对数据进行unpivot,这样就可以inner join,判断job是否匹配,因为subprofession为0,或者是否有精确的subprofessions:

WITH UserProf AS
(   SELECT  DISTINCT
            Users.UserID,
            p.Profession,
            p.SubProfession
    FROM    Users
            CROSS APPLY
            (VALUES
                (Profession1, SubProfession1),
                (Profession2, SubProfession2),
                (Profession3, SubProfession3),
                (Profession4, SubProfession4)
            ) p (Profession, SubProfession)
    WHERE   Users.UserID = @UserID
)
SELECT  Jobs.*, 
        MatchType = CASE WHEN MIN(UserProf.SubProfession) = 0 THEN 'All Subprofession' ELSE 'Exact subprofession' END
FROM    Jobs
        INNER JOIN UserProf
            ON UserProf.Profession = Jobs.Profession
            AND UserProf.SubProfession IN (0, Jobs.SubProfession)
GROUP BY Jobs.JobID, Jobs.Profession, Jobs.SubProfession;

Example on SQL-Fiddle

【讨论】:

尽管使用了exists关键字,第一个查询是否也可以在ms访问环境中工作? 是的,Access 支持EXISTS,所以第一个查询可以正常工作。【参考方案2】:

我更愿意看两年前写的一个自我记录的查询,而不是我必须弄清楚它在做什么的查询。当然,对我来说很困惑的事情可能是别人的简单。

鉴于子专业槽中的通配符为零,意思是“专业匹配,不用担心子专业”,我会将查询作为两组的并集来处理。

Set 1 是与用户的职业相匹配的所有工作的集合,其中 subprofession =0。 Set 2 是与用户的职业/副职业二元组匹配的所有工作的集合。

因此,第一步是为每个用户获取与子专业无关的不同专业的列表。这与专业工作有内在联系。

第二步是为每个用户获取不同的二元组列表,即子专业在哪里很重要。这与专业和子专业的工作有内在联系。

如果您愿意,每个连接都可以附加一个指示 MatchLevel 的列,即第一组中的 ProfessionOnly 和第二组中的 Both,但是您可以看到相同的工作列出了两次,一次用于一般匹配,一次用于特定匹配.

【讨论】:

以上是关于sql 查询的正确语法和 WHERE EXISTS 替代方案的主要内容,如果未能解决你的问题,请参考以下文章

sql 中exists 在where中怎样用?

使用 WHERE NOT EXISTS 的 SQL 查询出错

Exists 和Not Exists使用

如何在 SQL 子查询中使用 WHERE EXISTS?

SQL WHERE EXISTS 掩盖了子查询中的错误

Excel SQL - Where 子句语法不正确