Select (transact-sql)

Алан-э-Дейл       29.03.2024 г.

The HTMLSelectElement type

To interact with element in JavaScript, you use the type.

The type has the following useful properties:

  • – returns the zero-based index of the selected option. The is if no option is selected. If the element allows multiple selections, the returns the of the first option.
  • – returns the property of the first selected option element if there is one. Otherwise, it returns an empty string.
  • – returns if the element allows multiple selections. It is equivalent to the attribute.

The property

To select a element, you use the DOM API like or .

The following example illustrates how to get the index of the selected option:

How it works:

  • First, select the and elements using the method.
  • Then, attach a click event listener to the button and show the selected index using the method when the button is clicked.

The property

The property of the element depends on the element and its HTML attribute:

  • If no option is selected, the property of the select box is an empty string.
  • If an option is selected and has a attribute, the property of the select box is the value of the selected option.
  • If an option is selected and has no attribute, the property of the select box is the text of the selected option.
  • If multiple options are selected, the property of the select box is derived from the first selected option based on the previous two rules.

See the following example:

In this example:

  • If you select the first option, the property of the is empty.
  • If you select the last option, the property of the select box is because the selected option has no attribute.
  • If you select the second or third option, the value property will be or .

Introduction to SQL WHERE clause

To select specific rows from a table, you use a clause in the statement. The following illustrates the syntax of the clause in the statement:

The clause appears immediately after the clause. The clause contains one or more logical expressions that evaluate each row in the table. If a row that causes the condition evaluates to true, it will be included in the result set; otherwise, it will be excluded.

Note that SQL has three-valued logic which are TRUE, FALSE, and UNKNOWN. It means that if a row causes the condition to evaluate to FALSE or NULL, the row will not be returned.

Note that the logical expression that follows the clause is also known as a predicate. You can use various operators to form the row selection criteria used in the clause.

The following table shows the SQL comparison operators:

Operator Meaning
= Equal to
<> (!=) Not equal to
< Less than
> Greater than
<= Less than or equal
>= Greater than or equal

To form a simple expression, you use one of the operators above with two operands that can be either column name on one side and a literal value on the other, for example:

It asks a question: “Is salary greater than 1000?”.

Or you can use column names on both sides of an operator such as:

This expression asks another question: “Is the min salary less than the max salary?”.

The literal values that you use in an expression can be numbers, characters, dates, and times, depending on the format you use:

  • Number: use a number that can be an integer or a decimal without any formatting e.g., 100, 200.5
  • Character: use characters surrounded by either single or double quotes e.g., “100”, “John Doe”.
  • Date: use the format that the database stores. It depends on the database system e.g., MySQL uses format to store the date data.
  • Time: use the format that the database system uses to store the time. For example, MySQL uses to store time data.

Besides the statement, you can use the clause in the or statement to specify which rows to be updated or deleted.

SELECT statement – Syntax

All SQL commands are important and needed, especially these 4 most commonly used – SELECT, INSERT, UPDATE, DELETE.
Therefore, saying that the SELECT statement is the most important one is not true. It’s as important as others are but it’s definitely most commonly used. Being able to write a SELECT to get exactly what you wanted is a very desirable knowledge these days. Besides writing a statement that returns the correct result, you should almost
(if you write a one-time query and it takes 2 seconds instead of 0.1 seconds, you can live with that)
always make sure that the query is written in an optimal way.

Let’s take a look at the Transact-SQL SELECT statement syntax:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

— Syntax for SQL Server and Azure SQL Database  

<SELECTstatement>::=

WITH{XMLNAMESPACES,<common_table_expression>,…n}

<query_expression>

ORDERBY{order_by_expression|column_positionASC|DESC}

,…n

<FORClause>

OPTION(<query_hint>,…n)

<query_expression>::=

{<query_specification>|(<query_expression>)}

{UNIONALL|EXCEPT|INTERSECT}

<query_specification>|(<query_expression>)…n

<query_specification>::=

SELECTALL|DISTINCT

TOP(expression)PERCENTWITHTIES

<select_list>

INTOnew_table

FROM{<table_source>},…n

WHERE<search_condition>

<GROUPBY>

HAVING<search_condition>

I’ll simplify this syntax to focus on the things I want to explain in this article:

1
2
3
4
5
6
7
8

SELECTTOPXattributes&values

FROMfirst_table

INNERLEFTRIGHTJOINsecond_tableONcondition(s)

…otherjoinsifneeded

WHEREcondition(s)

GROUPBYsetofattributes

HAVINGcondition(s)forgroupby

ORDERBYlistattributesandorder;

SQL WHERE examples

We will use the table to demonstrate how to select data from the table using the clause.

SQL  clause with numeric comparison examples

The following query finds employees who have salaries greater than 14,000 and sorts the result set based on the salary in descending order.

The following query finds all employees who work in the department id 5.

SQL clause with characters example

SQL is case-insensitive. However, when it comes to the values in the comparisons, it is case-sensitive. For instance, the following query finds the employee whose last name is .

However, if you use or , no row will be returned.

SQL clause with dates examples

To get all employees who joined the company after , you use the following query:

If you want to find the employees who joined the company in 1999, you have several ways:

  1. Use the function to get the year data from the column and use the equal to (=) operator to form the expression.
  2. Use two expressions with the operator.
  3. Use the operator.

The following statement illustrates the first way:

In this tutorial, we have shown you how to use the SQL clause to filter data based on a specified condition.

2.1. Determination of input data (FROM clause processing)

The input data used by a simple SELECT query is a set of N rows
each M columns wide.

If the FROM clause is omitted from a simple SELECT statement, then the
input data is implicitly a single row zero columns wide (i.e. N=1 and
M=0).

If a FROM clause is specified, the data on which a simple SELECT query
operates comes from the one or more tables or subqueries (SELECT statements
in parentheses) specified following the FROM keyword. A subquery specified
in the table-or-subquery following the FROM clause in a
simple SELECT statement is
handled as if it was a table containing the data returned by executing the
subquery statement. Each column of the subquery has the
and of the corresponding expression
in the subquery statement.

If there is only a single table or subquery in the FROM
clause, then the input data used by the SELECT statement is the contents of the
named table. If there is more than one table or subquery in FROM clause
then the contents of all tables and/or subqueries
are joined into a single dataset for the simple SELECT statement to operate on.
Exactly how the data is combined depends on the specific join-operator and
join-constraint used to connect the tables or subqueries together.

All joins in SQLite are based on the cartesian product of the left and
right-hand datasets. The columns of the cartesian product dataset are, in
order, all the columns of the left-hand dataset followed by all the columns
of the right-hand dataset. There is a row in the cartesian product dataset
formed by combining each unique combination of a row from the left-hand
and right-hand datasets. In other words, if the left-hand dataset consists of
Nleft rows of
Mleft columns, and the right-hand dataset of
Nright rows of
Mright columns, then the cartesian product is a
dataset of
Nleft×Nright
rows, each containing
Mleft+Mright columns.

If the join-operator is «CROSS JOIN», «INNER JOIN», «JOIN» or a comma
(«,») and there is no ON or USING clause, then the result of the join is
simply the cartesian product of the left and right-hand datasets.
If join-operator does have ON or USING clauses, those are handled according to
the following bullet points:

  • If there is an ON clause then the ON expression is
    evaluated for each row of the cartesian product as a
    . Only rows for which the expression evaluates to
    true are included from the dataset.

  • If there is a USING clause
    then each of the column names specified must exist in the datasets to
    both the left and right of the join-operator. For each pair of named
    columns, the expression «lhs.X = rhs.X» is evaluated for each row of
    the cartesian product as a . Only rows for which
    all such expressions evaluates to true are included from the
    result set. When comparing values as a result of a USING clause, the
    normal rules for handling affinities, collation sequences and NULL
    values in comparisons apply. The column from the dataset on the
    left-hand side of the join-operator is considered to be on the left-hand
    side of the comparison operator (=) for the purposes of collation
    sequence and affinity precedence.

    For each pair of columns identified by a USING clause, the column
    from the right-hand dataset is omitted from the joined dataset. This
    is the only difference between a USING clause and its equivalent ON
    constraint.

  • If the NATURAL keyword is in the join-operator then an
    implicit USING clause is added to the join-constraints. The implicit
    USING clause contains each of the column names that appear in both
    the left and right-hand input datasets. If the left and right-hand
    input datasets feature no common column names, then the NATURAL keyword
    has no effect on the results of the join. A USING or ON clause may
    not be added to a join that specifies the NATURAL keyword.

  • If the join-operator is a «LEFT JOIN» or «LEFT OUTER JOIN», then
    after
    the ON or USING filtering clauses have been applied, an extra row is
    added to the output for each row in the original left-hand input
    dataset that corresponds to no rows at all in the composite
    dataset (if any). The added rows contain NULL values in the columns
    that would normally contain values copied from the right-hand input
    dataset.

When more than two tables are joined together as part of a FROM clause,
the join operations are processed in order from left to right. In other
words
, the FROM clause (A join-op-1 B join-op-2 C) is computed as
((A join-op-1 B) join-op-2 C).

Понимание операторов SELECT

Как упоминалось во введении, SQL-запросы почти всегда начинаются с оператора . SELECT используется в запросах, чтобы указать, какие столбцы из таблицы должны быть возвращены в наборе результатов. Запросы также почти всегда включают , который используется для указания таблицы, к которой будет обращаться оператор.

Как правило, SQL-запросы следуют этому синтаксису:

Например, следующий оператор вернет весь столбец из таблицы:

Вы можете выбрать несколько столбцов из одной таблицы, разделяя их имена запятыми, например:

Вместо того, чтобы называть конкретный столбец или набор столбцов, вы можете следовать за оператором со звездочкой (), которая служит заполнителем, представляющим все столбцы в таблице. Следующая команда возвращает каждый столбец из таблицы :

WHERE используется в запросах для фильтрации записей, которые удовлетворяют указанному условию, и любые строки, которые не удовлетворяют этому условию, исключаются из результата. Предложение обычно соответствует следующему синтаксису:

Оператор сравнения в предложении WHERE определяет способ сравнения указанного столбца со значением. Вот некоторые распространенные операторы сравнения SQL:

Оператор Что он делает
= тесты для равенства
!= тесты для неравенства
тесты для меньше, чем
> тесты для больше
тесты для менее чем или равный к
>= тесты для больше чем или равный к
BETWEEN проверяет лежит ли в заданном диапазоне
IN проверяет содержатся ли строки в наборе значений
EXISTS тесты на соответствие строки существует при заданных условиях
LIKE проверяет совпадает ли значение с указанной строкой
IS NULL тесты для `NULL` значения
IS NOT NULL тесты для всех других значений, чем `NULL`

Например, если вы хотите найти размер обуви Ирмы, вы можете использовать следующий запрос:

SQL допускает использование подстановочных знаков, и это особенно удобно при использовании в предложениях WHERE. Знаки процента () представляют ноль или более неизвестных символов, а подчеркивания () представляют один неизвестный символ. Они полезны, если вы пытаетесь найти конкретную запись в таблице, но не уверены, что эта запись. Чтобы проиллюстрировать это, скажем, что вы забыли любимое блюдо нескольких своих друзей, но вы уверены, что это конкретное блюдо начинается с буквы «t». Вы можете найти его имя, выполнив следующий запрос:

Основываясь на вышеприведенном выводе, мы видим, что блюдо — это тофу.

Могут быть случаи, когда вы работаете с базами данных, в которых есть столбцы или таблицы с относительно длинными или трудно читаемыми именами. В этих случаях вы можете сделать эти имена более читабельными, создав псевдоним с ключевым словом . Псевдонимы, созданные с помощью , являются временными и существуют только на время запроса, для которого они созданы:

Здесь мы сказали SQL отображать столбец как, столбец как, а столбец как .

Примеры, которые мы рассмотрели до этого момента, включают в себя некоторые из наиболее часто используемых ключевых слов и предложений в запросах SQL. Они полезны для базовых запросов, но они бесполезны, если вы пытаетесь выполнить вычисление или получить скалярное значение (одно значение, а не набор из нескольких различных значений) на основе ваших данных. Это где агрегатные функции вступают в игру.

Example — Select Individual Fields from a Table

You can also use the SQL SELECT statement to select individual fields from the table, as opposed to all fields from the table.

In this example, we have a table called suppliers with the following data:

supplier_id supplier_name city state
100 Microsoft Redmond Washington
200 Mountain View California
300 Oracle Redwood City California
400 Kimberly-Clark Irving Texas
500 Tyson Foods Springdale Arkansas
600 SC Johnson Racine Wisconsin
700 Dole Food Company Westlake Village California
800 Flowers Foods Thomasville Georgia
900 Electronic Arts Redwood City California

Now let’s demonstrate how to use the SELECT statement to select individual columns from a table. Enter the following SELECT statement:

Try It

SELECT supplier_name, city
FROM suppliers
WHERE supplier_id > 500
ORDER BY supplier_name ASC, city DESC;

4 records should be selected. These are the results that you should see:

supplier_name city
Dole Food Company Westlake Village
Electronic Arts Redwood City
Flowers Foods Thomasville
SC Johnson Racine

SQL — Обновление данных

Бывают такие случаи, когда данные вставил в таблицу и они больше никогда не меняются. Но в реальной жизни нередко данные подвержены изменениям и у нас должна быть возможность сделать это.

Минимальная команда изменения данных:

UPDATE таблица
SET колонка1 = значение, колонка2 = значение . . .
WHERE фильтр

В секции WHERE мы можем писать такие же условия, как мы делали и при SELECT. В остальном в принципе все понятно.

Давайте посмотрим на содержимое строки с ID = 14:

SELECT * FROM phone WHERE phoneid = 14;

Результат:

+---------+-----------+----------+---------+--------+
| phoneid | firstname | lastname | phone   | cityid |
+---------+-----------+----------+---------+--------+
|      14 | Mary      | NULL     | 4184719 |   NULL |
+---------+-----------+----------+---------+--------+
1 row in set (0.00 sec)

Здесь у нас Мэри, но у нее не было указано фамилии. Давайте обновим эту строку и укажим фамилию.

UPDATE phone
SET lastname = 'Poppins'
WHERE 

Стоп, что указать в качестве фильтра WHERE? Можно указать имя, но если в базе данных будет несколько записей людей с именем Mary, то мы обновим их все. Не думаю, что мы этого хотим.

По номеру телефона. . . Возможно это сработает, если номер действительно уникальный.

Если у нас есть колонка с уникальными значениями, то лучше использовать ее, тогда мы точно будем знать, что обновлена именно нужная нам запись. Именно поэтому создают в базах данных ключевые поля, как я это сделал с phoneid и самый простой способ добиться уникальности – сделать колонку автоматически увеличиваемой или сохранять в ней что-то типа уникального GUID.

Некоторые базы данных даже не позволяют обновлять данные в таблице, если в ней нет уникальной колонки, потому что база данных в таком случае не может гарантировать, что будет обновлена или удалена именно нужная колонка.

Если забыть про наличие phoneid, которую я заведомо и продуманно создал, то мы можем вставить в таблицу две записи с абсолютно одинаковыми значениями. Допустим, что у нас есть такая таблица:

+-----------+-----------+-----------+
| firstname | lastname  | cityid    |
+-----------+-----------+-----------+
| Mary      | NULL      | 4184719   |
| Mary      | NULL      | 4184719   |
| NULL      | NULL      | NULL      |
+-----------+-----------+-----------+

Как мы можем обновить вторую запись Mary, без уникального кода id? А первую? Да все равно какую из них! Записи идентичны и с обновлением проблема. Самый простой способ – удалить обе записи и вставить новые. Да, это решит проблему, но все же.

Именно поэтому некоторые не разрешают изменять данные, если нет первичного ключа, который гарантирует уникальность данных, потому что хотя бы этот ключ и будет различать записи.

С другой стороны, при наличии первичного уникального ключа, которым является personid, желательно использовать его:

UPDATE phone
SET lastname = 'Poppins'
WHERE personid = 14

Если ты потерялся и все еще не понимаешь, что такое первичный ключ, мы еще будем говорить на тему ключей, когда будем создавать таблицы. Я помню мне тоже на первом этапе знакомства с базами данных было не совсем понятно было что это такое, зачем это нужно. Пока просто помните, что первичный ключ, это колонка (может и не одна), которая гарантирует уникальность каждой строки.

Мы можем обновлять не одну, а сразу несколько колонок, указав их значения через запятую. Давайте изменим сразу фамилию и телефон:

UPDATE phone
SET lastname = 'Poppins',
    phone = '48171738'
WHERE personid = 14

Юзабилити-тестСкопировать ссылку

Я провела небольшое юзабилити-тестирование, в котором я попросила нескольких людей с ограниченными возможностями воспользоваться гибридным селектом. Были протестированы следующие устройства и инструменты с использованием последних версий Chrome 81, Firefox 76, Safari 13:

  • Компьютер только с мышью.
  • Компьютер только с клавиатурой.
  • VoiceOver на macOS с помощью клавиатуры.
  • NVDA в Windows с помощью клавиатуры.
  • VoiceOver на iPhone и iPad в Safari

Все эти тесты дали желаемый результат, но я уверена, что можно было бы провести ещё больше юзабилити-тестов с более разнообразными устройствами и широким диапазоном лиц. Если у вас есть возможность протестировать на других устройствах или с другими инструментами — такими как JAWS, Dragon и подобным — пожалуйста, расскажите мне, как прошёл тест.

Во время теста была обнаружена проблема. В частности, проблема связана с настройкой VoiceOver «Использовать виртуальный курсор VoiceOver». Если пользователь откроет селект с помощью этого курсора, вместо нативного покажется кастомный селект.

Больше всего мне нравится в этом подходе то, как он совмещает всё самое лучшее из обоих миров без нанесения ущерба функциональности.

  • Пользователи мобильных устройств и планшетов получают нативный селект, предлагающий лучший пользовательский интерфейс по сравнению с кастомным селектом, включая преимущества производительности.
  • Пользователи клавиатур получают возможность взаимодействия с нативным селектом в соответствии с их ожиданиями.
  • Вспомогательные технологии спокойно могут взаимодействовать с нативным селектом.
  • Пользователи мыши получают возможность взаимодействовать с расширенным кастомным селектом.

Данный подход обеспечивает необходимую для каждого функциональность без дополнительного громоздкого кода, реализующего функции нативного селекта.

Не поймите меня неправильно, этот метод не является универсальным решением для всех. Он может являться рабочим для простых селектов, но, вероятно, не будет работать в случаях со сложным взаимодействием. В этих случаях нам нужно использовать ARIA и JavaScript для восполнения пробелов и создания действительно доступного селекта.

Примечание касательно селекта-менюСкопировать ссылку

Давайте вернёмся к третьему сценарию нашего списка селектов. Если вы помните, это выпадающий список, который всегда имеет отмеченный вариант (например, сортировка). Я отнесла его к серой области как и меню или селект.

Идея такая: много лет назад этот тип выпадающего списка реализовывался в основном с помощью нативного . В настоящее время часто можно увидеть что он реализован с нуля с помощью кастомных стилей (доступных или нет). И мы получаем селект, стилизованный под меню.

Примеры селектов, выступающих в качестве меню.

 — это вид меню. Оба имеют схожую семантику и поведение, особенно в случае, когда один вариант всегда выбран. Теперь позвольте мне упомянуть критерий из WCAG 3.2.2 о полях (уровень A):

Давайте применим это на практике. Представьте себе сортируемый список студентов. Может быть визуально очевидно, что сортировка происходит незамедлительно, но это не обязательно так для всех людей. Таким образом, при использовании , мы рискуем нарушить правила WCAG, поскольку контент страницы изменился, а это попадает под понятие «изменение контекста».

Чтобы соблюсти критерий, мы должны уведомить пользователя о действии до того, как он начнёт взаимодействовать с элементом или же поставить сразу после списка, чтобы подтвердить изменения.

Тем не менее, использование наряду с созданием пользовательского меню является хорошим подходом, когда речь заходит о несложных меню, требующих изменение содержимого страницы. Просто помните, что от вашего решения зависит объём работ, необходимых для создания полностью доступного компонента. Это как раз тот случай, когда гибридный селект может выручить.

Селект, выпадающий список, навигация, меню… название имеет значениеСкопировать ссылку

Во время изучения данной темы я думала обо всех тех названиях, которыми разбрасываются, когда говорят о селектах. Наиболее общие из них — «выпадающий список» и «меню». Есть два типа ошибок при наименовании, которые мы можем допустить: дать одинаковые названия разным элементам или дать разные названия одинаковым элементам.

Перед тем, как мы двинемся дальше, позвольте мне внести ясность касательно использования термина «выпадающий список». Вот как я его понимаю:

Множество интерфейсов могут выглядеть похоже на выпадающий список. Но просто назвать элемент «выпадающим списком» — всё равно что использовать слово «рыба» для описания животного. Какое семейство рыб? Рыба-клоун не то же самое, что и акула. То же касается и выпадающих списков.

Отличаем рыбу-клоуна от акулы.

Подобно тому, как в море существует много разных видов рыб, есть множество компонентов, о которых мы можем вести речь, столкнувшись со словосочетанием «выпадающий список».

  • Меню: список команд или действий, которые пользователь может исполнить на странице.
  • Навигация: список ссылок, используемых для перемещения по сайту.
  • Селект: контрол формы , показывающий пользователю список опций, которые он может в ней выбрать.

Решение, о каком типе выпадающих списков мы ведём речь, может быть туманным. Вот несколько примеров из веба, подходящих под мою классификацию вышеупомянутых элементов. Оно основано на моём исследовании, и иногда, когда я не могу найти подходящий ответ, интуитивно основано на моём опыте.

Мир выпадающих списков: пять сценариев их использования в вебе. Более подробное описание — в таблице ниже.

Ожидаемое поведение Тип списка
1 Ожидается, что выбранный вариант отправится внутри формы на сервер, например, возраст. Селект
2 Выпадающему списку не нужен выбранный вариант, например, список действий: копировать, вставить и вырезать. Меню
3 Выбранный вариант влияет на контент, например, сортировка списка. Меню или селект, подробности чуть позже.
4 Выпадающий список содержит ссылки на другие страницы, например, большая навигация со ссылками на разделы сайта. Открывающаяся навигация
5 Содержимое выпадающего меню — не список, например, выбор даты. Что-то другое, что не следует называть выпадающим списком

Не все воспринимают интернет и взаимодействуют с ним одинаково. Именование пользовательских интерфейсов и определение дизайн-паттернов — фундаментальный процесс, хотя и с достаточным пространством для личной интерпретации.

Вот тип выпадающего списка, который определенно можно назвать меню. Его использование является горячей темой при обсуждении доступности. Я не буду много говорить об этом здесь, но позвольте мне просто подчеркнуть, что тег устарел и не рекомендуется к использованию. Вот подробное руководство по инклюзивным меню и меню-кнопкам (в переводе на «Веб-стандартах», прим. редактора), включая объяснение почему ARIA-роль не следует использовать для навигации по сайту.

Мы даже не коснулись других элементов, которые попадают в довольно серую зону, что делает классификацию выпадающих списков ещё более туманной из-за недостака практических примеров использования от WCAG.

Уфф… получилось много. Давайте забудем обо всём этом беспорядке с выпадающими списками и сосредоточимся исключительно на элементе .

UPDATE from SELECT: The MERGE statement

The MERGE statement is used to manipulate (INSERT, UPDATE, DELETE) a target table by referencing a source table for the matched and unmatched rows. The MERGE statement can be very useful for synchronizing the table from any source table.

Now, if we go back to our position, the MERGE statement can be used as an alternative method for updating data in a table with those in another table. In this method, the reference table can be thought of as a source table and the target table will be the table to be updated. The following query can be an example of this usage method.

1
2
3
4
5
6
7
8
9

MERGEPersonsASPer

USING(SELECT*FROMAddressList)ASAddr

ONAddr.PersonID=Per.PersonID

WHENMATCHEDTHEN

UPDATESET

Per.PersonPostCode=Addr.PostCode,

Per.PersonCityName=Addr.City;

SELECT*FROMPersons

Now let’s tackle the previous update from a select query line by line.

1 MERGEPersonsASPer

We have typed the Persons table after the MERGE statement because it is our target table, which we want to update, and we gave Per alias to it in order to use the rest of the query.

1 USING(SELECT*FROMAddressList)ASAddr

After the USING statement, we have specified the source table.

1 ONAddr.PersonID=Per.PersonID

With the help of this syntax, the join condition is defined between the target and source table.

1
2

WHENMATCHEDTHEN

UPDATESETPer.PersonPostCode=Addr.PostCode;

In this last line of the query, we chose the manipulation method for the matched rows. Individually for this query, we have selected the UPDATE method for the matched rows of the target table. Finally, we added the semicolon (;) sign because the MERGE statements must end with the semicolon signs.

Гость форума
От: admin

Эта тема закрыта для публикации ответов.