Сама проблема проста, но я не могу найти решение, которое решает ее в одном запросе, и вот моя «абстракция» проблемы, позволяющая дать более простое объяснение:
Я оставлю свое исходное объяснение в силе, но вот набор образцов данных и ожидаемый результат:
Хорошо, вот несколько примеров данных, я разделил пары пустой строкой
-------------
| 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» не существует, он должен искать строку, где NAME является «Bruce» - но только вернуть «Джон», если существуют и «Брюс», и «Джон», или, конечно, существует только «Джон».
Также обратите внимание, что он должен иметь возможность возвращать несколько строк на запрос, которые соответствуют указанным выше критериям, но, конечно, с разными комбинациями идентификаторов / имен, и что приведенное выше объяснение является просто упрощением реальной проблемы.
Я мог быть полностью ослеплен своим собственным кодом и ходом мыслей, но я просто не могу этого понять.
Насколько кроссплатформенным должен быть ответ? Я мог бы придумать что-то, что работало бы в SQL Server, но не в MySQL ...
Георгий: Я пояснил этот пример с помощью некоторых примеров данных и результата, которого я ожидал бы после одного запроса. AviewAnew: Все, что угодно.


Вы можете использовать объединения вместо существующих, и это может улучшить план запроса в тех случаях, когда оптимизатор недостаточно умен:
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 )
попробуй это:
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
Вы можете присоединить исходную таблицу к самой себе с помощью ВНЕШНЕГО СОЕДИНЕНИЯ следующим образом:
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')
как это.
Кажется, я получаю сообщение об ошибке при попытке этого в mysql, только postgre?
Я тестировал его в SQL Server 2005.
В PostgreSQL, я думаю, это было бы так:
SELECT DISTINCT ON (id) id, name
FROM mytable
ORDER BY id, name = 'John' DESC;
Обновление - ложные сортировки перед истиной - изначально у меня было наоборот. Обратите внимание, что DISTINCT ON - это функция PostgreSQL, а не часть стандартного SQL. Что здесь происходит, так это то, что он показывает вам только первую строку для любого заданного идентификатора, с которым он сталкивается. Поскольку мы упорядочиваем по погоде, имя John, строки с именем John будут выделены поверх всех остальных имен.
В вашем втором примере это будет:
SELECT DISTINCT ON (key) key, col
FROM mytable
ORDER BY key, col = 'Foo' DESC;
Это даст вам:
1 - Foo
2 - Foo
3 - Bar
4 - Foo
Я сам придумал решение, но оно довольно сложное и медленное - и не подходит для более сложных запросов:
SELECT *
FROM users
WHERE name = "bruce"
OR (
name = "john"
AND NOT id
IN (
SELECT id
FROM posts
WHERE name = "bruce"
)
)
Нет альтернатив без тяжелых стыков и т. д.?
Хорошо, вот несколько примеров данных, я разделил пары пустой строкой
-------------
| 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
Я решил это выше, но этот запрос ужасно неэффективен для таблиц лагеров, иначе?
Это довольно похоже на то, что вы написали, но должно быть довольно быстрым, поскольку 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 |
+----+-----+
Вот пример, который работает в 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
Не нужно усложнять этот процесс, можно просто использовать MAX() и group by ....
select id, max(col) from foo group by id
Не могли бы вы прояснить этот вопрос на примере? т.е. предоставление минимальных наборов данных и решений, которые вы хотите получить на их основе?