有没有更好的方法来编写此查询?

时间:2010-10-14 18:24:31

标签: sql tsql sql-server-2008

因此,假设我正在尝试获取属于某个用户组的所有用户的列表。易:

SELECT *
  FROM users, usergroups
 WHERE usergroups.user_group_id = 1

现在,假设我想获得一个属于某个用户组的所有用户的列表,以及一封以.edu结尾的电子邮件。

SELECT *
  FROM users, usergroups
 WHERE usergroups.user_group_id = 1
   AND users.email LIKE '%.edu'

这很有效。现在假设我们想要获得上述所有内容以及属于用户组2的用户 - 但我们并不关心第二组的电子邮件地址。此查询不起作用:

SELECT *
  FROM users, usergroups
 WHERE usergroups.user_group_id IN (1,2)
   AND users.email LIKE '%.edu'

因为它会过滤第二组中的用户。现在我正在做这样的事情:

SELECT *
  FROM users as usrs, usergroups as groups1, usergroups as groups2
 WHERE (groups1s.user_group_id = 1 AND users.email LIKE '%.edu')
    OR groups2.user_group_id = 2

这给了我想要的结果,但我讨厌它看起来和工作的方式。有更清洁的方法吗?

修改

我没有在上一次迭代中包含联接。以下是查询的真实含义:

SELECT *
FROM users as usrs JOIN
usergroups as groups1 on usrs.group_id = groups1.group_id JOIN
usergroups as groups2 on usrs.group_id = groups2.group_id
WHERE (groups1.user_group_id = 1 AND users.email LIKE '%.edu')
OR groups2.user_group_id = 2

7 个答案:

答案 0 :(得分:5)

不需要使用不同的别名选择两次用户组。你可以做到:


SELECT *
  FROM users as usrs, usergroups
 WHERE (usergroups.user_group_id = 1 AND users.email LIKE '%.edu')
    OR usergroups.user_group_id = 2

或者,甚至更好(使用加入):


SELECT *
  FROM users as usrs 
  JOIN usergroups on usergroups.userid = users.id
 WHERE (usergroups.user_group_id = 1 AND users.email LIKE '%.edu')
    OR usergroups.user_group_id = 2

答案 1 :(得分:2)

由于SQL语法,你正在做的事情可能会起作用,即使它看起来很丑陋。对我没有意义的是为什么用户ID上的用户和用户组之间没有连接:

...其中usergroups.user_id = users.user_id

除非我遗漏了某些内容,因为您正在进行用户和用户组之间的交叉连接。如果你列出每个表中的列,它会帮助我们一大堆。

答案 2 :(得分:2)

我会稍微考虑一下,并假设用户和用户组之间存在关系。然后你就像这样编写你的查询:

SELECT *
    FROM users as usrs
        INNER JOIN usergroups as groups1
            ON usrs.GroupID = groups1.GroupID
    WHERE (groups1.user_group_id = 1 AND usrs.email LIKE '%.edu')
        OR groups1.user_group_id = 2

答案 3 :(得分:1)

修复你的JOIN。

对于用户组中的每个行,您总是从用户返回每个行(暂时忽略电子邮件过滤器),因为您没有JOIN,无论他们属于哪个组至。你有一个简单的交叉加入/笛卡儿产品。

然后,使用UNION或UNION ALL删除OR。或者将OR留在原地。

 SELECT *
  FROM
     users as usrs
     JOIN
     usergroups as groups1 ON usrs.foo = groups1.foo
 WHERE
    groups1s.user_group_id = 1 AND users.email LIKE '%.edu'
UNION --maybe UNION ALL
SELECT *
  FROM
     users as usrs
     JOIN
     usergroups as group2  ON  usrs.foo = groups2.foo
WHERE
     groups2.user_group_id = 2

答案 4 :(得分:1)

关于Michael Goldshteyn所说的关于使用JOINS重新编写它的内容,以及Joe Stefnelli关于交叉连接的评论,您的初始查询将被重写:

SELECT *
FROM users 
JOIN user_groups ON users.user_group_id = user_groups.user_group_id
WHERE users.email LIKE '%.edu'
AND user_groups.user_group_id = 1

添加第二组将导致:

SELECT *
FROM users AS users
JOIN user_groups AS user_groups ON users.user_group_id = user_groups_1.user_group_id
WHERE ( ( users.email LIKE '%.edu' AND user_groups_1.user_group_id = 1 )
        OR user_groups_2.user_group_id = 2 ) 

或者你甚至可以做一个工会(我个人不会这样做):

SELECT *
FROM users AS users_1 
JOIN user_groups AS user_groups_1 ON users_1.user_group_id = user_groups_1.user_group_id
WHERE users_1.email LIKE '%.edu'
AND user_groups_1.user_group_id = 1
UNION
SELECT *
FROM users AS users_2
JOIN user_groups AS user_groups_2 ON users_2.user_group_id = user_groups_2.user_group_id
AND user_groups_2.user_group_id = 2

答案 5 :(得分:1)

我发现你的最新编辑没有任何问题。你可以做一个Union,但我认为这将是更加丑陋的。

答案 6 :(得分:1)

优化查询。

对于大型表格(可能不是这种情况),您应该考虑查询可能带来的性能损失。所以我更喜欢以下方法:首先我选择一些临时表我要使用的行,然后我删除不需要的行,最后我选择结果集并删除内存中的对象。注意:此查询使用 Transact SQL

select u.*, g.user_group_id into #TEMP from users u, usergroups g where u.group_id = g.group_id and g.user_group_id in (1,2) 
delete from #TEMP where user_group_id = 1 and email not like '%.edu'
select * from #TEMP
drop table #TEMP