← Назад к вопросам
Что такое row?
1.0 Junior🔥 101 комментариев
#Pandas и обработка данных#SQL и базы данных
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
ROW: строка в SQL и контексты использования
Что такое ROW в разных контекстах
ROW имеет несколько значений в зависимости от контекста:
- Физическая строка в таблице (обычное понимание)
- ROW конструктор в SQL (кортеж значений)
- Window функция в SQL (обработка по строкам)
- Концепция в данных (наблюдение/запись)
1. ROW конструктор (ROW constructor)
ROW в SQL создает кортеж значений (tuple):
-- Синтаксис
ROW(value1, value2, value3)
-- Пример 1: создать кортеж
SELECT ROW(1, 'Alice', 'alice@test.com') AS user_record;
-- Результат: (1,Alice,alice@test.com)
-- Пример 2: сравнение кортежей
SELECT *
FROM users
WHERE ROW(first_name, last_name) = ROW('Alice', 'Smith');
-- Это эквивалентно:
WHERE first_name = 'Alice' AND last_name = 'Smith';
2. ROW_NUMBER(): Window функция
ROW_NUMBER() нумерует строки в окне (partition):
-- Синтаксис
SELECT
ROW_NUMBER() OVER (ORDER BY column) AS row_num,
*
FROM table;
-- Пример 1: простая нумерация
SELECT
ROW_NUMBER() OVER (ORDER BY created_at) AS row_num,
user_id,
created_at
FROM users;
-- Результат:
-- row_num | user_id | created_at
-- 1 | 5 | 2024-01-01
-- 2 | 3 | 2024-01-02
-- 3 | 1 | 2024-01-03
-- Пример 2: нумерация по группам
SELECT
ROW_NUMBER() OVER (PARTITION BY category ORDER BY sales DESC) AS rank_in_category,
product_name,
category,
sales
FROM products;
-- Результат:
-- rank_in_category | product_name | category | sales
-- 1 | iPhone 15 | Electronics| 50000
-- 2 | MacBook Pro | Electronics| 45000
-- 1 | Nike Air Max | Fashion | 15000
-- 2 | Adidas Ultraboost | Fashion | 14000
3. Практические примеры ROW_NUMBER()
Пример 1: Удалить дубликаты
-- Найти дубликаты
SELECT
ROW_NUMBER() OVER (PARTITION BY email ORDER BY created_at) AS dup_num,
*
FROM users;
-- Результат:
-- email | dup_num | created_at
-- alice@test.com | 1 | 2024-01-01 ← первый (оставить)
-- alice@test.com | 2 | 2024-01-02 ← дубликат
-- alice@test.com | 3 | 2024-01-03 ← дубликат
-- bob@test.com | 1 | 2024-01-01 ← первый (оставить)
-- Удалить дубликаты (оставить только первый)
WITH ranked_users AS (
SELECT
ROW_NUMBER() OVER (PARTITION BY email ORDER BY created_at) AS dup_num,
*
FROM users
)
DELETE FROM users
WHERE user_id IN (
SELECT user_id FROM ranked_users WHERE dup_num > 1
);
Пример 2: Получить N-й элемент в группе
-- Топ 3 продукта по каждой категории
WITH ranked_products AS (
SELECT
ROW_NUMBER() OVER (PARTITION BY category ORDER BY sales DESC) AS rank,
product_name,
category,
sales
FROM products
)
SELECT *
FROM ranked_products
WHERE rank <= 3;
Пример 3: Заказы по пользователям (последний заказ каждого)
WITH ranked_orders AS (
SELECT
ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY created_at DESC) AS order_rank,
user_id,
order_id,
created_at,
amount
FROM orders
)
SELECT *
FROM ranked_orders
WHERE order_rank = 1; -- последний заказ каждого пользователя
4. ROW vs RANK vs DENSE_RANK
Все три — window функции, но отличаются в обработке ties (ничьих):
SELECT
product_name,
sales,
ROW_NUMBER() OVER (ORDER BY sales DESC) AS row_num,
RANK() OVER (ORDER BY sales DESC) AS rank,
DENSE_RANK() OVER (ORDER BY sales DESC) AS dense_rank
FROM products;
-- Результат (если есть ties):
-- product_name | sales | row_num | rank | dense_rank
-- iPhone | 1000 | 1 | 1 | 1
-- Samsung | 1000 | 2 | 1 | 1 ← tie
-- Pixel | 900 | 3 | 3 | 2 ← скачок на 3
-- MacBook | 800 | 4 | 4 | 3
-- ROW_NUMBER: просто 1, 2, 3, 4 (непрерывно)
-- RANK: 1, 1, 3, 4 (скачок после tie)
-- DENSE_RANK: 1, 1, 2, 3 (без скачков)
5. Общее понимание ROW в анализе данных
ROW = строка (наблюдение) в датасете:
-- Каждое SELECT выбирает ROWS (строки)
SELECT * FROM users LIMIT 10;
-- Результат: 10 rows returned
-- COUNT(*) считает количество ROW'ов
SELECT COUNT(*) as total_rows FROM users;
-- GROUP BY группирует ROW'ы
SELECT category, COUNT(*) as row_count
FROM products
GROUP BY category;
6. ROW в Python/Pandas
import pandas as pd
df = pd.DataFrame({
'user_id': [1, 2, 3],
'name': ['Alice', 'Bob', 'Charlie'],
'age': [25, 30, 35]
})
# Каждая строка = ROW
print(df) # 3 rows (3 наблюдения)
# Итерация по ROW'ам
for index, row in df.iterrows():
print(f"Row {index}: {row['name']}, age {row['age']}")
# Row 0: Alice, age 25
# Row 1: Bob, age 30
# Row 2: Charlie, age 35
# Доступ к конкретному ROW'у
row_0 = df.iloc[0] # первая строка
print(row_0['name']) # 'Alice'
# df.shape[0] = количество ROW'ов
print(df.shape[0]) # 3
7. Window функции: практический пример
Задача: для каждого товара найти его позицию в рейтинге по продажам
SELECT
product_id,
product_name,
category,
sales,
-- ROW_NUMBER по продажам (без дублирования номеров)
ROW_NUMBER() OVER (ORDER BY sales DESC) AS overall_rank,
-- ROW_NUMBER внутри категории
ROW_NUMBER() OVER (PARTITION BY category ORDER BY sales DESC) AS category_rank,
-- Средние продажи по категории
AVG(sales) OVER (PARTITION BY category) AS category_avg_sales,
-- Кумулятивная сумма
SUM(sales) OVER (ORDER BY sales DESC ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS cumulative_sales
FROM products
ORDER BY sales DESC;
8. ROW конструктор для сравнений
-- Вместо этого
WHERE first_name = 'Alice'
AND last_name = 'Smith'
AND email = 'alice@smith.com'
-- Можно написать так
WHERE ROW(first_name, last_name, email) = ROW('Alice', 'Smith', 'alice@smith.com')
-- Или для множественных сравнений
WHERE ROW(first_name, last_name) IN (
ROW('Alice', 'Smith'),
ROW('Bob', 'Jones'),
ROW('Charlie', 'Brown')
);
9. Практический пример: Когортный анализ
-- Задача: найти, как долго пользователи остаются активными
WITH user_activity AS (
SELECT
user_id,
DATE_TRUNC('month', event_date)::DATE AS month,
ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY DATE_TRUNC('month', event_date)) AS months_since_signup,
COUNT(*) as events
FROM user_events
GROUP BY user_id, DATE_TRUNC('month', event_date)
)
SELECT
months_since_signup,
COUNT(DISTINCT user_id) as active_users,
AVG(events) as avg_events_per_user
FROM user_activity
GROUP BY months_since_signup
ORDER BY months_since_signup;
-- Результат показывает сколько пользователей активно на месяц 1, 2, 3 после signup
-- месяц | активных_юзеров | среднее_событий
-- 1 | 10000 | 25
-- 2 | 7000 | 20
-- 3 | 4200 | 15
-- (видим падение retention)
10. ROW в контексте различных БД
PostgreSQL:
SELECT ROW(1, 'test');
SELECT ROW_NUMBER() OVER (ORDER BY id);
MySQL:
SELECT ROW_NUMBER() OVER (ORDER BY id) AS rn FROM table;
-- ROW конструктор не поддерживается, используй CONCAT вместо
SQL Server:
SELECT ROW_NUMBER() OVER (ORDER BY id) AS rn FROM table;
-- ROW конструктор не поддерживается
SQLite:
SELECT ROW_NUMBER() OVER (ORDER BY id) AS rn FROM table;
-- ROW конструктор не поддерживается
Памятка для собеседования
| Термин | Значение | Пример |
|---|---|---|
| ROW | Строка в таблице | Каждая запись данных |
| ROW() | Конструктор кортежа | ROW(val1, val2) = ROW(a, b) |
| ROW_NUMBER() | Window функция нумерации | ROW_NUMBER() OVER (ORDER BY ...) |
| RANK() | Window функция рейтинга (с пробелами) | RANK() OVER (ORDER BY ...) |
| DENSE_RANK() | Window функция рейтинга (без пробелов) | DENSE_RANK() OVER (ORDER BY ...) |
| Rows in DataFrame | Наблюдения в Pandas | df.shape[0] = количество строк |
Когда использовать:
- ✅ ROW_NUMBER(): когда нужна простая нумерация (по порядку)
- ✅ RANK(): когда нужны рейтинги с учетом ties
- ✅ DENSE_RANK(): когда нужны рейтинги без пробелов
- ✅ ROW конструктор: для множественных сравнений
Важное: Row часто встречается в контексте "N-th row", "last row", "first row" — это обозначения конкретных строк в наборе данных.