Як перевірити, чи має підзапит чітко один чіткий результат та вказане значення?


10

Я виявив, що пишу таке:

select 'yes' 
where exists(select * from foo where val=1)
and not exists(select * from foo where val<>1);

і цікаво, чи існує більш стислий спосіб без шкоди для занадто великої читабельності.

Я знайшов один із способів, який я публікую як відповідь, але я не зовсім задоволений цим і дуже зацікавлений у альтернативах

У цьому випадку valце унікально всередині foo- копій немає


Я правильно розумію, що ви хочете рівно один рядок в результаті підпиту?
Erwin Brandstetter


Той, кого ви згадуєте у назві. Я не був впевнений, чи повинен це бути один результат після або перед "чітким".
Ервін Брандштеттер

Ага так, це :) Я досить заплутано посилався на підзапит у своїй відповіді - ваш набагато конкретніший і гнучкіший, наприклад, ви також можете використовувати count(distinct val), хоча в моєму реальному випадку це не має ніякого значення
Джек каже спробуйте topanswers.xyz

Відповіді:


8

Лаконічний, швидкий (особливо з багатьма рядами), мій фаворит, що стосується читабельності, а також працював би з дупами:

SELECT count(*) = 1 AND min(val) = 1 FROM foo;

Повертає TRUE/ FALSE.. або NULL- лише у випадку, якщо рівно один рядок з val IS NULL, тому що count()ніколи не повертає NULLчи не містить рядка.

Другий 1у прикладі просто трапляється таким же, як і перший, через ваш приклад.


Запит у питанні не відповідає NULLзначень. Розглянемо просту демонстрацію:

CREATE TABLE foo (id int, val int);
INSERT INTO foo VALUES (1, 1),(2, NULL);

SELECT 'yes' 
WHERE      EXISTS(SELECT * FROM foo WHERE val =  1)
AND    NOT EXISTS(SELECT * FROM foo WHERE val <> 1);

IS DISTINCT FROMце виправить це, але воно все-таки може вийти з ладу в дублікатах, valякі ви виключили для цього випадку.


Ваша відповідь справно працює.
Повернення 'yes'/ немає рядка

Я хотів би віддати перевагу цій коротшій формі. Не забувайте, що PostgreSQL (на відміну від Oracle) має належний booleanтип .

SELECT array_agg(val) = array[1] FROM foo;

Повернення TRUE/ FALSE/ NULL.


чудово, дякую, я знав, що буде кращий спосіб :)
Джек каже спробувати topanswers.xyz

5

Варіація відповіді на Ервіна. Ні COUNT()взагалі, тільки MIN()і MAX(). Це може бути трохи ефективніше з великим столом і (не у вашому випадку) дублікатом val:

SELECT MIN(val) = 1 AND MAX(val) = 1 FROM foo;

+1 спасибі Він обробляє нулі та дублікати, звичайно, (якщо такі були)
Джек каже спробувати topanswers.xyz

@Jack: Так. У вашому столі є нулі? Або ви хочете відповіді в обох випадках (з і без)?
ypercubeᵀᴹ

жодної шахти немає - я можу використовувати будь-яке :)
Джек каже спробувати topanswers.xyz

Було б набагато швидше у великих таблицях із відповідним індексом, але виконує однаково за відсутності такого індексу - як при тестуванні результатів запитів.
Ервін Брандштеттер


1

Це один повертається true, falseабо порожній результат:

 select j.val is null 
 from foo left join foo as j on j.val <> foo.val 
 where foo.val = 1 limit 1;

на перший погляд, це, здається, не повертається, falseякщо є значення fooде val<>1?
Джек каже, спробуйте topanswers.xyz

@JackDouglas О, вибачте. Я зрозумів завдання неправильно в перший раз. Виправлено.
Grayhemp

Працює - окрім NULLзначення, яке не виключено в даному випадку.
Ервін Брандстеттер

@ErwinBrandstetter NULLможна опрацювати, використовуючи, IS [NOT] DISTINCT FROMя думаю.
Grayhemp

1
@grayhemp: Не в цьому випадку. LEFT JOIN foo j ON j.val <> foo.valне вдається виявити рядок, з якого j.val IS NULLслід почати. Якщо ви включите його до ON j.val IS DISTINCT FROM foo.valсебе, то вам потрібно буде встановити інший стовпець, jвизначений NOT NULLдля розгляду двох випадків. Але жоден додатковий стовпець не визначений.
Ервін Брандстеттер
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.