4

我正在创建一个非常复杂的动态 sql,它必须为每个用户返回一行,但现在我必须加入一对多表。我做了一个外连接以确保我至少得到一行(并且可以检查 null 以查看该表中是否有数据)但我必须确保我只从这个外连接部分返回一行,如果有多个此用户的第二个表中的行。到目前为止,我想出了这个:(sybase)

SELECT a.user_id
FROM table1 a
    ,table2 b
WHERE a.user_id = b.user_id
AND a.sub_id = (
    SELECT min(c.sub_id)
    FROM table2 c
    WHERE b.sub_id = c.sub_id
    )

子查询在一对多表中为该特定用户找到最小值。

这行得通,但是当表 1 和表 2 变得非常大时,我担心执行相关子查询会带来麻烦。有没有更好的办法?我正在努力想出一种方法来让加入来做到这一点,但我没有看到它。还说“where rowcount=1”或“top 1”对我没有帮助,因为我不是要修复上面的查询,而是将上面的内容添加到已经很复杂的查询中。

4

6 回答 6

1

在 MySql 中,您可以确保任何查询最多返回 X 行使用

select *
from foo
where bar = 1
limit X;

不幸的是,我相当肯定这是一个 MySQL 特定的 SQL 扩展。但是,Google 搜索“mysql sybase limit”之类的内容可能会找到 Sybase 的等价物。

于 2008-10-27T14:37:29.103 回答
1

A few quick points:

  1. You need to have definitive business rules. If the query returns more than one row then you need to think about why (beyond just "it's a 1:many relationship - WHY is it a 1:many relationship?). You should come up with the business solution rather than just use "min" because it gives you 1 row. The business solution might simply be "take the first one", in which case min might be the answer, but you need to make sure that's a conscious decision.
  2. You should really try to use the ANSI syntax for joins. Not just because it's standard, but because the syntax that you have isn't really doing what you think it's doing (it's not an outer join) and some things are simply impossible to do with the syntax that you have.

Assuming that you end up using the MIN solution, here's one possible solution without the subquery. You should test it with various other solutions to make sure that they are equivalent in outcome and to see which performs the best.

SELECT
     a.user_id, b.*
FROM
     dbo.Table_1 a
LEFT OUTER JOIN dbo.Table_2 b ON b.user_id = a.user_id AND b.sub_id = a.sub_id
LEFT OUTER JOIN dbo.Table_2 c ON c.user_id = a.user_id AND c.sub_id < b.sub_id
WHERE
     c.user_id IS NULL

You'll need to test this to see if it's really giving what you want and you might need to tweak it, but the basic idea is to use the second LEFT OUTER JOIN to ensure that there are no rows that exist with a lower sub_id than the one found in the first LEFT OUTER JOIN (if any is found). You can adjust the criteria in the second LEFT OUTER JOIN depending on the final business rules.

于 2008-10-27T15:11:37.677 回答
0

也许你的例子太简单了,但我会使用一个组:

选择
  a.user_id
从
  表1a
    LEFT OUTER JOIN table2 b ON (a.user_id = b.user_id)
通过...分组
  a.user_id

我担心唯一的其他方法是使用嵌套查询:

此查询与您的示例之间的区别是“子表”只生成一次,但是在您的示例中,您为 table1 中的每一行生成一个“子表”(但可能取决于编译器,因此您可能希望使用查询分析仪检查性能)。

选择
  a.user_id,
  b.sub_id
从
  表1a
    左外连接 (
      选择
        用户身份,
        min(sub_id) 作为 sub_id,
      从
        表2
      通过...分组
        用户身份
    ) b 开启 (a.user_id = b.user_id)

此外,如果您的查询变得非常复杂,我会使用临时表来简化代码,这可能会花费更多的处理时间,但会使您的查询更易于维护。

临时表示例是:

选择
  用户身份
进入
  #表格1
从
  表格1
在哪里
  ......

选择
  a.user_id,
  min(b.sub_id) 作为 sub_id,
进入
  #table2
从
  #table1 一个
    INNER JOIN table2 b ON (a.user_id = b.user_id)
通过...分组
  a.user_id

选择
  一个。*,
  b.sub_id
从
  #table1 一个
    左外连接 #table2 b ON (a.user_id = b.user_id)
于 2008-10-27T13:55:53.930 回答
0

怎么样:

select a.user_id 
from table1 a
where exists (select null from table2 b 
              where a.user_id = b.user_id 
             )
于 2008-10-27T14:21:11.147 回答
0

首先,我相信您尝试编写的查询作为您的示例是:

select a.user_id 
from table1 a, table2 b 
where a.user_id = b.user_id 
and b.sub_id = (select min(c.sub_id) 
                from table2 c 
                where b.user_id = c.user_id)

除了你想要一个外连接(我认为有人编辑了 Oracle 语法)。

select a.user_id 
from table1 a
left outer join table2 b on a.user_id = b.user_id 
where b.sub_id = (select min(c.sub_id) 
                from table2 c 
                where b.user_id = c.user_id)
于 2008-10-27T14:51:34.813 回答
-1

Well, you already have a query that works. If you are concerned about the speed you could

  • Add a field to table2 which identifies which sub_id is the 'first one' or

  • Keep track of table2's primary key in table1, or in another table

于 2008-10-27T15:16:10.053 回答