问题本身很简单,但我无法弄清楚在一个查询中做到这一点的解决方案,而这是我对问题的“抽象”,以便做出更简单的解释:
我会让原始的explenation成立,但这里有一组示例数据和我期望的结果:
好的,所以这里是一些样本数据,我用空行分隔对
-------------
| 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
,其中我有两列说ID
和NAME
,它们共同构成了表格的主键。现在我想选择ID=1
的内容然后首先检查它是否可以找到NAME
具有值“John”的行,如果“John”不存在则应该查找{ {1}}是“布鲁斯” - 但如果“布鲁斯”和“约翰”都存在或只有“约翰”存在,则只返回“约翰”。
另请注意,它应该能够为每个查询返回多个符合上述条件的行,但当然具有不同的ID /名称组合,并且上述说明只是对实际问题的简化。
我可以完全被自己的代码和思路所蒙蔽,但我无法理解这一点。
答案 0 :(得分: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 |
+----+-----+
答案 1 :(得分: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')
像那样。
答案 2 :(得分:1)
无需将此过于复杂,您只需使用MAX()
和group by ...
select id, max(col) from foo group by id
答案 3 :(得分: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
答案 4 :(得分:0)
我自己想出了一个解决方案,但它有点复杂和缓慢 - 它也不能很好地扩展到更高级的查询:
SELECT *
FROM users
WHERE name = "bruce"
OR (
name = "john"
AND NOT id
IN (
SELECT id
FROM posts
WHERE name = "bruce"
)
)
没有重型连接等没有替代方案?
答案 5 :(得分: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
我确实在上面解决了这个问题,但是对于更大的表,这个查询是非常低效的,还是其他方式吗?
答案 6 :(得分: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
答案 7 :(得分:-1)
您可以使用联接而不是exists,这可能会在优化程序不够智能的情况下改进查询计划:
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 )
答案 8 :(得分:-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