sql #sql-server #tsql
#sql #sql-сервер #tsql
Вопрос:
У меня есть таблица, в которой хранятся сотрудники (идентификатор, имя и пол). Мне нужно случайным образом получить двух мужчин и двух женщин.
CREATE TABLE employees
(
id INT,
name VARCHAR (10),
gender VARCHAR (1),
);
INSERT INTO employees VALUES (1, 'Mary', 'F');
INSERT INTO employees VALUES (2, 'Jake', 'M');
INSERT INTO employees VALUES (3, 'Ryan', 'M');
INSERT INTO employees VALUES (4, 'Lola', 'F');
INSERT INTO employees VALUES (5, 'Dina', 'F');
INSERT INTO employees VALUES (6, 'Paul', 'M');
INSERT INTO employees VALUES (7, 'Tina', 'F');
INSERT INTO employees VALUES (8, 'John', 'M');
Моя попытка заключается в следующем:
SELECT TOP 2 *
FROM employees
WHERE gender = 'F'
ORDER BY NEWID()
UNION
SELECT TOP 2 *
FROM employees
WHERE gender = 'M'
ORDER BY NEWID()
Но это не работает, так как я не могу поместить два order by
в один и тот же запрос.
Комментарии:
1. Примечание: для строки фиксированной длины в 1 символ —
VARCHAR(1)
это плохой выбор — для каждой записи потребуется 1-3 байта памяти. Если длина всего одна —CHAR(1)
вместо этого используйте a, которая всегда будет составлять всего 1 байт — для каждой отдельной записи.2. Также, пожалуйста, по умолчанию
UNION ALL
используется значение «вообще», если вы явно не хотите, чтобы поведениеUNION
удаляло дубликаты из обоих наборов (это дороже, потому что может потребоваться дополнительная сортировка, особенно когда задействовано много столбцов, поэтому всякий раз, когда я вижуUNION
в PR, я всегда спрашиваю, действительно ли им это нужно).
Ответ №1:
Почему бы просто не использовать row_number()
? Один метод без подзапроса:
SELECT TOP (4) WITH TIES e.*
FROM employees
WHERE gender IN ('M', 'F')
ORDER BY ROW_NUMBER() OVER (PARTITION BY gender ORDER BY newid());
Это немного менее эффективно, чем использование ROW_NUMBER()
в подзапросе.
Или, забавный метод будет использовать APPLY
:
select e.*
from (values ('M'), ('F')) v(gender) cross apply
(select top (2) e.*
from employees e
where e.gender = v.gender
order by newid()
) e;
Комментарии:
1. Второй действительно интересен.
Ответ №2:
Вы не можете поместить an ORDER BY
в комбинируемый запрос (первый) из UNION
. Однако вы можете использовать ORDER BY
, если преобразуете каждый из них в табличное выражение.
Например:
select *
from (
SELECT TOP 2 *
FROM employees
WHERE gender = 'F'
ORDER BY newid()
) x
UNION ALL
select *
from (
SELECT TOP 2 *
FROM employees
WHERE gender = 'M'
ORDER BY newid()
) y
Результат:
id name gender
--- ----- ------
5 Dina F
4 Lola F
2 Jake M
3 Ryan M
Смотрите Пример выполнения в SQL Fiddle.