3

问题本身很简单,但我无法找出在一个查询中解决问题的解决方案,这是我对问题的“抽象”,以便进行更简单的解释:

我会保留我原来的解释,但这里有一组示例数据和我期望的结果:

好的,这是一些示例数据,我用空行分隔了对

-------------
| Key |  Col | (Together they from a Unique Pair)
--------------
|  1     Foo |
|  1     Bar |
|            |
|  2     Foo |
|            |
|  3     Bar |
|            |
|  4     Foo |
|  4     Bar |
--------------

我期望的结果是,在运行一次查询之后,它需要能够在一个查询中选择这个结果集:

1 - Foo
2 - Foo
3 - Bar
4 - Foo

原文解释:

我有一个表,把它称为TABLE我有两列的地方IDNAME它们一起构成了表的主键。现在我想在哪里选择一些东西,ID=1然后首先检查它是否可以找到NAME值“John”的行,如果“John”不存在,它应该寻找NAME“Bruce”所在的行 - 但只返回“John”如果“布鲁斯”和“约翰”都存在,或者当然只有“约翰”存在。

另请注意,它应该能够为每个查询返回几行匹配上述条件但当然具有不同的 ID/名称组合,并且上述解释只是对实际问题的简化。

我可能完全被自己的代码和思路蒙蔽了双眼,但我就是想不通。

4

9 回答 9

4

这与您编写的内容非常相似,但应该相当快,因为​​在这种情况下,NOT EXISTS 比 NOT IN... 更有效

mysql> select * from foo;
+----+-----+
| id | col |
+----+-----+
|  1 | Bar | 
|  1 | Foo | 
|  2 | Foo | 
|  3 | Bar | 
|  4 | Bar | 
|  4 | Foo | 
+----+-----+

SELECT id
     , col
  FROM foo f1 
 WHERE col = 'Foo' 
  OR ( col = 'Bar' AND NOT EXISTS( SELECT * 
                                     FROM foo f2
                                    WHERE f1.id  = f2.id 
                                      AND f2.col = 'Foo' 
                                 ) 
     ); 

+----+-----+
| id | col |
+----+-----+
|  1 | Foo | 
|  2 | Foo | 
|  3 | Bar | 
|  4 | Foo | 
+----+-----+
于 2008-09-29T21:41:07.177 回答
1

您可以使用这样的 OUTER JOIN 将初始表连接到自身:

create table #mytest
   (
   id           int,
   Name         varchar(20)
   );
go

insert into #mytest values (1,'Foo');
insert into #mytest values (1,'Bar');
insert into #mytest values (2,'Foo');
insert into #mytest values (3,'Bar');
insert into #mytest values (4,'Foo');
insert into #mytest values (4,'Bar');
go

select distinct
   sc.id,
   isnull(fc.Name, sc.Name) sel_name
from
   #mytest sc

   LEFT OUTER JOIN #mytest fc
      on (fc.id = sc.id
          and fc.Name = 'Foo')

像那样。

于 2008-09-29T21:06:29.770 回答
1

无需使这过于复杂,您只需使用MAX()group by ...

select id, max(col) from foo group by id
于 2010-10-14T13:28:17.430 回答
0

试试这个:

select top 1 * from (
SELECT 1 as num, * FROM TABLE WHERE ID = 1 AND NAME = 'John'
union 
SELECT 2 as num, * FROM TABLE WHERE ID = 1 AND NAME = 'Bruce'
) t
order by num 
于 2008-09-29T21:06:27.307 回答
0

我自己想出了一个解决方案,但它有点复杂和缓慢 - 它也不能很好地扩展到更高级的查询:

SELECT *
FROM users
WHERE name = "bruce"
OR (
    name = "john"
    AND NOT id
    IN (
        SELECT id
        FROM posts
        WHERE name = "bruce"
    )
)

没有重连接等没有替代品?

于 2008-09-29T21:11:07.763 回答
0

好的,这是一些示例数据,我用空行分隔了对

-------------
| Key |  Col | (Together they from a Unique Pair)
--------------
|  1     Foo |
|  1     Bar |
|            |
|  2     Foo |
|            |
|  3     Bar |
|            |
|  4     Foo |
|  4     Bar |
--------------

我期望的结果是:

1 - Foo
2 - Foo
3 - Bar
4 - Foo

我确实在上面解决了它,但是对于较大的表来说,该查询的效率非常低,还有其他方式吗?

于 2008-09-29T21:18:11.147 回答
0

下面是一个适用于 SQL Server 2005 及更高版本的示例。这是一个有用的模式,您希望根据自定义排序选择顶行(或前 n 行)。这将使您不仅可以在具有自定义优先级的两个值中进行选择,还可以选择任何数字。您可以使用 ROW_NUMBER() 函数和 CASE 表达式:

CREATE TABLE T (id int, col varchar(10));

INSERT T VALUES (1, 'Foo')
INSERT T VALUES (1, 'Bar')
INSERT T VALUES (2, 'Foo')
INSERT T VALUES (3, 'Bar')
INSERT T VALUES (4, 'Foo')
INSERT T VALUES (4, 'Bar')

SELECT id,col
FROM 
(SELECT id, col,
    ROW_NUMBER() OVER (
    PARTITION BY id 
    ORDER BY 
    CASE col 
    WHEN 'Foo' THEN 1
    WHEN 'Bar' THEN 2 
    ELSE 3 END
    ) AS RowNum 
    FROM T
) AS X
WHERE RowNum = 1
ORDER BY id
于 2008-10-02T21:48:14.293 回答
-1

您可以使用连接而不是存在,这可能会在优化器不够智能的情况下改进查询计划:

SELECT f1.id
  ,f1.col
FROM foo f1 
LEFT JOIN foo f2
  ON f1.id = f2.id
  AND f2.col = 'Foo'
WHERE f1.col = 'Foo' 
  OR ( f1.col = 'Bar' AND f2.id IS NULL )
于 2008-09-29T20:57:20.057 回答
-1

在 PostgreSQL 中,我相信它会是这样的:

SELECT DISTINCT ON (id) id, name
FROM mytable
ORDER BY id, name = 'John' DESC;

更新 - 在真之前的错误排序 - 我最初是倒退的。请注意,DISTINCT ON 是 PostgreSQL 功能,而不是标准 SQL 的一部分。这里发生的是它只向您显示它遇到的任何给定 id 的第一行。由于我们按天气排序,名称为 John,因此将选择名为 John 的行而不是所有其他名称。

对于您的第二个示例,它将是:

SELECT DISTINCT ON (key) key, col
FROM mytable
ORDER BY key, col = 'Foo' DESC;

这会给你:

1 - Foo
2 - Foo
3 - Bar
4 - Foo
于 2008-09-29T21:08:34.990 回答