Въведение
За да работите с данни в база данни, трябва да можете ефективно да извличате и насочвате конкретни записи. Като използвате клаузи за филтриране във вашите заявки, можете да добавите конкретни критерии, за да върнете само най-подходящите записи.
В това ръководство ще разгледаме някои от най-често срещаните филтриращи операции, налични в PostgreSQL, и ще покажем как да ги използвате, за да стесните фокуса на вашите изявления. Ще покажем как да тестваме спрямо характеристики в отделни записи с WHERE
клаузи, как да групирате записи заедно, за да обобщите информация с GROUP BY
, как да филтрирате групи от записи с HAVING
подклауза и как да зададете максималния брой върнати редове с LIMIT
клауза.
Използване на WHERE
клауза за дефиниране на критерии за съвпадение
Един от най-често срещаните и широко полезни начини да посочите изискванията на заявката си е WHERE
клауза. WHERE
клаузата ви позволява да дефинирате действителни критерии за търсене на изрази за заявка, като посочите условия, които трябва да са верни за всички съвпадащи записи.
WHERE
клаузите работят чрез дефиниране на булеви изрази, които се проверяват спрямо всеки кандидат ред данни. Ако резултатът от израза е false, редът ще бъде премахнат от резултатите и няма да бъде върнат или да продължи към следващия етап на обработка. Ако резултатът от израза е верен, той отговаря на критериите за търсене и ще продължи за всяка по-нататъшна обработка като ред кандидат.
Основният синтаксис на WHERE
клаузата изглежда така:
SELECT * FROM my_table WHERE <condition>;
<condition>
може да бъде всичко, което води до булева стойност. В PostgreSQL булева стойност е всяка от TRUE
, FALSE
или NULL
.
Условията често се формират с помощта на един или повече от следните оператори:
=
:равно на>
:по-голямо от<
:по-малко от>=
:по-голямо или равно на<=
:по-малко или равно на<>
или!=
:не е равноAND
:логическият оператор "и" — свързва две условия и връщаTRUE
ако и двете условия саTRUE
OR
:логически оператор "или" — свързва две условия и връщаTRUE
ако поне едно от условията еTRUE
IN
:стойността се съдържа в списъка, сериите или диапазона, които следваBETWEEN
:стойността се съдържа в диапазона на минималните и максималните стойности, които следват, включителноIS NULL
:съвпада, ако стойността еNULL
NOT
:отрича булевата стойност, която следваEXISTS
:заявката, която следва, съдържа резултатиLIKE
:съвпада с шаблон (използвайки заместващите знаци%
за да съответства на 0 или повече знака и_
за да съответства на един знак)ILIKE
:съвпада с шаблон (използвайки заместващите знаци%
за да съответства на 0 или повече знака и_
за да съвпадне с един знак), нечувствителни към главни буквиSIMILAR TO
:съвпада с шаблон, използващ диалекта на регулярен израз на SQL~
:съвпада с шаблон, използващ POSIX регулярни изрази, чувствителен към главни букви~*
:съвпада с шаблон, използващ POSIX регулярни изрази, без значение на малки и големи!~
:не съвпада с шаблон, използващ POSIX регулярни изрази, чувствителен към главни букви!~*
:не съвпада с шаблон, използващ POSIX регулярни изрази, без значение на малки и големи
Докато горният списък представя някои от най-често срещаните тестови конструкции, има много други оператори, които дават булеви резултати, които могат да се използват във връзка с WHERE
клауза.
Примери, използващи WHERE
Една от най-често срещаните и ясни проверки е за равенство, като се използва =
оператор. Тук проверяваме дали всеки ред в customer
таблицата има last_name
стойност, равна на Smith
:
SELECT * FROM customer WHERE last_name = 'Smith';
Можем да добавим допълнителни условия към това, за да създадем съставни изрази с помощта на логически оператори. Този пример използва AND
клауза за добавяне на допълнителен тест срещу first_name
колона. Валидни редове трябва да отговарят и на двете дадени условия:
SELECT * FROM customer WHERE first_name = 'John' AND last_name = 'Smith';
По същия начин можем да проверим дали е изпълнено някое от поредица от условия. Тук проверяваме редове от address
таблица, за да видите дали zip_code
стойността е равна на 60626 или на neighborhood
колона е равна на низа "Roger's Park". Използваме две единични кавички, за да укажем, че трябва да се търси буквален единичен кавички:
SELECT * FROM address WHERE zip_code = '60626' OR neighborhood = 'Roger''s Park';
IN
операторът може да работи като сравнение между редица стойности, увити в скоби. Ако има съвпадение с някоя от дадените стойности, изразът е TRUE
:
SELECT * FROM customer WHERE last_name IN ('Smith', 'Johnson', 'Fredrich');
Тук проверяваме срещу модел на низ, използвайки LIKE
. %
работи като заместващ знак, съответстващ на нула или повече знака, така че "Pete", "Peter" и всеки друг низ, който започва с "Pete", ще съвпада:
SELECT * FROM customer WHERE last_name LIKE 'Pete%';
Бихме могли да направим подобно търсене, използвайки ~*
оператор за проверка за съвпадения, използвайки POSIX регулярни изрази, без да се съобразява с главния регистър. В този случай проверяваме дали стойността на last_name
започва с "d" и съдържа поднизът "on", който би съвпадал с имена като "Диксън", "Доналд" и "Девон":
SELECT * FROM customer WHERE last_name ~* '^D.*on.*';
Можем да проверим дали номерът на улицата е в рамките на блока от 4000 адреси с помощта на BETWEEN
и AND
оператори за дефиниране на включващ диапазон:
SELECT * FROM address WHERE street_number BETWEEN 4000 AND 4999;
Тук можем да покажем всеки customer
записи, които имат социалноосигурителни номера, които не са дълги 9 цифри. Използваме LENGTH()
оператор, за да получите броя на цифрите в полето и <>
за да проверите за неравенство:
SELECT * FROM customer WHERE LENGTH(SSN) <> 9;
Използване на GROUP BY
клауза за обобщаване на множество записи
GROUP BY
клаузата е друг много често срещан начин за филтриране на резултати чрез представяне на множество резултати с един ред. Основният синтаксис на GROUP BY
клаузата изглежда така:
SELECT <columns> FROM some_table GROUP BY <columns_to_group>
Когато GROUP BY
клауза се добавя към израз, той казва на PostgreSQL да покаже един ред за всяка уникална стойност за дадена колона или колони. Това има някои важни последици.
Тъй като GROUP BY
клаузата е начин за представяне на множество редове като един ред, PostgreSQL може да изпълни заявката само ако може да изчисли стойност за всяка от колоните, които има задача да покаже. Това означава, че всяка колона, идентифицирана с SELECT
част от изявлението трябва да бъде или:
- включен в
GROUP BY
клауза, за да се гарантира, че всеки ред има уникална стойност - Абстрахирано, за да се обобщят всички редове във всяка група
На практика това означава, че всички колони в SELECT
списъкът не е включен в GROUP BY
клаузата трябва да използва агрегатна функция, за да произведе единичен резултат за колоната за всяка група.
Примери, използващи GROUP BY
За примерите в този раздел да предположим, че имаме таблица, наречена pet
които сме дефинирали и попълнили така:
CREATE TABLE pet ( id SERIAL PRIMARY KEY, type TEXT, name TEXT, color TEXT, age INT);INSERT INTO pet (type, name, color, age) VALUES('dog', 'Spot', 'brown', 3),('dog', 'Rover', 'black', 7),('dog', 'Sally', 'brown', 1),('cat', 'Sabrina', 'black', 8),('cat', 'Felix', 'white', 4),('cat', 'Simon', 'orange', 8),('rabbit', 'Buttons', 'grey', 4),('rabbit', 'Bunny', 'brown', 8),('rabbit', 'Briony', 'brown', 6);
Най-простото използване на GROUP BY
е да се покаже диапазонът от уникални стойности за една колона. За да направите това, използвайте същата колона в SELECT
и GROUP BY
. Тук виждаме всички цветове, използвани в таблицата:
SELECT color FROM pet GROUP BY color;
color-------- black grey brown white orange(5 rows)
Докато преминавате отвъд една колона в SELECT
списък с колони, трябва или да добавите колоните към GROUP BY
клауза или използвайте агрегатна функция, за да произведете единична стойност за групата от представени редове.
Тук добавяме type
към GROUP BY
клауза, което означава, че всеки ред ще представлява уникална комбинация от type
и color
стойности. Добавяме и age
колона, обобщена от avg()
функция за намиране на средната възраст на всяка от групите:
SELECT type, color, avg(age) AS average_age FROM pet GROUP BY type, color;
type | color | average_age--------+--------+-------------------- rabbit | brown | 7.0000000000000000 cat | black | 8.0000000000000000 rabbit | grey | 4.0000000000000000 dog | black | 7.0000000000000000 dog | brown | 2.0000000000000000 cat | orange | 8.0000000000000000 cat | white | 4.0000000000000000(7 rows)
Агрегатните функции работят също толкова добре с една колона в GROUP BY
клауза. Тук намираме средната възраст на всеки вид животно:
SELECT type, avg(age) AS average_age FROM PET GROUP BY type;
type | average_age--------+-------------------- rabbit | 6.0000000000000000 dog | 3.6666666666666667 cat | 6.6666666666666667(3 rows)
Ако искаме да покажем най-старото от всеки тип животно, вместо това можем да използваме max()
функция на age
колона. GROUP BY
клаузата свива резултатите в същите редове, както преди, но новата функция променя резултата в другата колона:
SELECT type, max(age) AS oldest FROM pet GROUP BY type;
type | oldest--------+------- rabbit | 8 dog | 7 cat | 8(3 rows)
Използване на HAVING
клауза за филтриране на групи от записи
GROUP BY
клаузата е начин за обобщаване на данни чрез свиване на множество записи в един представителен ред. Но какво ще стане, ако искате да стесните тези групи въз основа на допълнителни фактори?
HAVING
Клаузата е модификатор за GROUP BY
клауза, която ви позволява да посочите условия, на които всяка група трябва да отговаря, за да бъде включена в резултатите.
Общият синтаксис изглежда така:
SELECT <columns> FROM some_table GROUP BY <columns_to_group> HAVING <condition>
Операцията е много подобна на WHERE
клауза, с разликата, че WHERE
филтрира единични записи и HAVING
филтрира групи от записи.
Примери, използващи HAVING
Използвайки същата таблица, която въведохме в последния раздел, можем да демонстрираме как HAVING
клаузата работи.
Тук групираме редовете на pet
таблица по уникални стойности в type
колона, намирайки минималната стойност на age
също така. HAVING
клаузата след това филтрира резултатите, за да премахне всички групи, при които възрастта не е по-голяма от 1:
SELECT type, min(age) AS youngest FROM pet GROUP BY type HAVING min(age) > 1;
type | youngest--------+---------- rabbit | 4 cat | 4(2 rows)
В този пример групираме редовете в pet
по техния цвят. След това филтрираме групите, които представляват само един ред. Резултатът ни показва всеки цвят, който се появява повече от веднъж:
SELECT color FROM pet GROUP BY color HAVING count(color) > 1;
color------- black brown(2 rows)
Можем да изпълним подобна заявка, за да получим комбинациите от type
и color
че само едно животно има:
SELECT type, color FROM pet GROUP BY type, color HAVING count(color) = 1;
type | color--------+-------- cat | black rabbit | grey dog | black cat | orange cat | white(5 rows)
Използване на LIMIT
клауза за задаване на максимален брой записи
LIMIT
клаузата предлага различен подход за съкращаване на записите, които вашата заявка връща. Вместо да елиминира редове с данни въз основа на критерии в самия ред, LIMIT
клаузата задава максималния брой записи, върнати от заявка.
Основният синтаксис на LIMIT
изглежда така:
SELECT * FROM my_table LIMIT <num_rows> [OFFSET <num_rows_to_skip>];
Тук <num_rows>
показва максималния брой редове за показване от изпълнената заявка. Това често се използва във връзка с ORDER BY
клаузи за получаване на редовете с най-екстремни стойности в определена колона. Например, за да получи петте най-добри точки на изпит, потребителят може да ORDER BY
score
колона и след това LIMIT
резултатите до 5.
Докато LIMIT
брои от горната част на резултатите по подразбиране, незадължителният OFFSET
ключова дума може да се използва за компенсиране на началната позиция, която използва. Всъщност това ви позволява да ранжирате в страници чрез резултати, като показвате броя на резултатите, дефинирани от LIMIT
и след това добавяне на LIMIT
номер към OFFSET
за да извлечете следната страница.
Примери, използващи LIMIT
Ще използваме pet
таблица от по-рано за примерите в този раздел.
Както бе споменато по-горе, LIMIT
често се комбинира с ORDER BY
клауза за изрично дефиниране на подреждането на редовете, преди да изрежете съответното число. Тук сортираме pet
записи според тяхната age
, от най-възрастния до най-младия. След това използваме LIMIT
за показване на първите 5 най-стари животни:
SELECT * FROM pet ORDER BY age DESC LIMIT 5;
type | name | color | age | id--------+---------+--------+-----+---- cat | Simon | orange | 8 | 6 cat | Sabrina | black | 8 | 4 rabbit | Bunny | brown | 8 | 8 dog | Rover | black | 7 | 2 rabbit | Briany | brown | 6 | 9(5 rows)
Без ORDER BY
клауза, LIMIT
ще направи селекции по напълно предвидим начин. Върнатите резултати могат да бъдат осъществени по реда на записите в таблицата или чрез индекси. Това не винаги е лошо.
Ако имаме нужда от запис за някое едно dog
в таблицата бихме могли да изградим заявка като тази. Имайте предвид, че макар резултатът да е труден за прогнозиране, това не е случаен избор и не трябва да се използва като такъв:
SELECT * FROM pet WHERE type = 'dog' LIMIT 1;
type | name | color | age | id------+------+-------+-----+---- dog | Spot | brown | 3 | 1(1 row)
Можем да използваме OFFSET
клауза за пагинация на резултатите. Включваме ORDER BY
клауза за дефиниране на конкретен ред за резултатите.
За първата заявка ограничаваме резултатите, без да указваме OFFSET
за да получите първите 3 най-млади записа:
SELECT * FROM pet ORDER BY age LIMIT 3;
type | name | color | age | id------+-------+-------+-----+---- dog | Sally | brown | 1 | 3 dog | Spot | brown | 3 | 1 cat | Felix | white | 4 | 5(3 rows)
За да получим следващите 3 най-млади, можем да добавим числото, дефинирано в LIMIT
към OFFSET
за да пропуснете резултатите, които вече сме изтеглили:
SELECT * FROM pet ORDER BY age LIMIT 3 OFFSET 3;
type | name | color | age | id --------+---------+-------+-----+---- rabbit | Buttons | grey | 4 | 7 rabbit | Briany | brown | 6 | 9 dog | Rover | black | 7 | 2(3 rows)
Ако добавим LIMIT
към OFFSET
отново ще получим следващите 3 резултата:
SELECT * FROM pet ORDER BY age LIMIT 3 OFFSET 6;
type | name | color | age | id--------+---------+--------+-----+---- cat | Simon | orange | 8 | 6 rabbit | Bunny | brown | 8 | 8 cat | Sabrina | black | 8 | 4(3 rows)
Това ни позволява да извличаме редове данни от заявка на управляеми парчета.
Заключение
Има много начини за филтриране и по друг начин ограничаване на резултатите, които получавате от заявките. Клаузи като WHERE
и HAVING
оценете потенциалните редове или групи от редове, за да видите дали отговарят на определени критерии. GROUP BY
клаузата ви помага да обобщите данните, като групирате заедно записи, които имат една или повече общи стойности на колони. LIMIT
клаузата предлага на потребителите възможността да зададат твърд максимум за броя на записите за извличане.
Научаването как тези клаузи могат да се прилагат, поотделно или в комбинация, ще ви позволи да извлечете конкретни данни от големи набори от данни. Модификаторите и филтрите на заявки са от съществено значение за превръщането на данните, които живеят в PostgreSQL, в полезни отговори.