Sql 是否有更好的方法编写此查询?

Sql 是否有更好的方法编写此查询?,sql,tsql,sql-server-2008,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'

假设我正在尝试获取属于某个用户组的所有用户的列表。简单:

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
        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
这给了我想要的结果,但我讨厌它的外观和工作方式。有没有更干净的方法

编辑

我在上一次迭代中没有包括连接。以下是查询的实际外观:

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

由于SQL语法的原因,您的操作方式可能会起作用,尽管它看起来更难看。对我来说没有意义的是,为什么在用户id上用户和用户组之间没有连接:

。。。其中usergroups.user\u id=users.user\u id

除非我遗漏了什么,因为您正在用户和用户组之间进行交叉连接。如果您在每个表中列出列,这将对我们有很大帮助。

修复连接

您总是为usergroups中的每一行返回用户的每一行(暂时忽略电子邮件筛选器),因为您没有加入,无论他们属于哪个组。你有一个简单的交叉连接/笛卡尔积

然后,使用UNION或UNION ALL删除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

根据Michael Goldshteyn所说的关于使用连接重新编写的内容,以及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 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
        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

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


SELECT *
  FROM users as usrs, usergroups
 WHERE (usergroups.user_group_id = 1 AND users.email LIKE '%.edu')
    OR usergroups.user_group_id = 2
或者更好(使用join):


我看不出你最近编辑的连接有什么问题。你可以做一个
联合
,但我认为在我看来那会更难看。

优化查询。 对于大型表(可能不是这样),您应该考虑查询可能带来的性能损失。因此,我更喜欢以下方法:首先,我将要处理的行选择到某个临时表中,然后删除不需要的行,最后,我选择结果集并删除内存中的对象。注意:此查询使用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

我将从符合ANSI标准开始,编写连接,而不是使用
符号。我无法想象这些查询中有任何一个能按预期工作。您正在生成所有表的叉积。你有链接用户和用户组的专栏吗?这两个表之间应该存在某种连接。我没有看到任何连接或where子句将这两个表连接在一起……您是有意在这里使用笛卡尔坐标系吗?我会将其更新为ansi-92语法,特别是如果您需要更干净的并且正在使用sql server 2008。我认为没有任何方法可以改变where子句中的布尔逻辑,尽管我猜这些查询更像是伪代码;假装我加入了。我的“真实”查询在表之间有连接。@SuperNES:发布你的“真实”查询。“真实”查询中有一大堆其他表,并且使用属于我雇主的数据模型,我不希望将其放在互联网上。我试图在这里抽象出核心问题。我认为我在上面发布的最后一个查询足以有效地定义这个问题。