#sql #sql-server #join #window-functions
#sql #sql-сервер #Присоединиться #окно-функции
Вопрос:
У меня есть одна таблица адресов, другая таблица купонов. Я хочу выбрать 10 купонов на адрес. Как бы я это сделал? Я знаю, что это очень просто, но я уже некоторое время не работаю с SQL и пытаюсь заново познакомиться с ним как можно лучше…
Таблица 1
Name Address
-------------------
Store 1 Address 1
Store 2 Address 2
Таблица 2
Coupons
--------
coupon1
coupon2
...
coupon19
coupon20
Комментарии:
1. Какие 10 купонов?
2. Всего в магазине 128 с купонами 128000. Каждому магазину потребуется по 100 купонов. Скажем, 1-100 для хранилища 1, 101-200 для хранилища 2 и так далее.
3. с SQL Server вы можете использовать номер строки. Вы объединяете две таблицы, затем запускаете команду номер строки и выбираете строки с номерами строк меньше 10. Вот пример
Ответ №1:
Вы можете использовать оконные функции:
select t1.*, t2.coupons
from (
select t1.*, row_number() over(order by id) rn
from table1 t1
) t1
inner join (
select t2.*, row_number() over(order by id) rn
from table2 t2
) t2 on (t2.rn - 1) / 10 = t1.rn
Идея состоит в том, чтобы перечислить строки каждой таблицы с помощью row_number()
, а затем объединить результаты с условием для номеров строк. Приведенный выше запрос дает вам 10 купонов на адрес.
Чтобы получить стабильный результат, вам нужен столбец (или набор столбцов) в каждой таблице, который однозначно идентифицирует каждую строку: я предполагал id
в обеих таблицах.
Ответ №2:
Вы хотите 10 купонов на магазин? 100 купонов на магазин? Ответ на ваш вопрос отличается от сообщения. Или, может быть, вы хотели бы равномерно распределить все доступные купоны по всем магазинам? Часть этого запроса строит данные, чтобы иметь возможность продемонстрировать результат, но главное, на чем следует сосредоточиться, — это использование NTILE (10) для разделения купонов на десять групп, к которым затем может быть применен ROW_NUMBER, который дает вам десять купонов на значение идентификатора, которые можно объединить…
WITH random_data AS
(
SELECT ROW_NUMBER() OVER (ORDER BY id) AS nums
FROM sysobjects
), store_info AS
(
SELECT ROW_NUMBER() OVER (ORDER BY nums) AS join_id,
'Store' CONVERT(VARCHAR(10),nums) AS StoreName,
'Address' CONVERT(VARCHAR(10),nums) AS StoreAddress
FROM random_data
), more_random_data AS
(
SELECT ROW_NUMBER() OVER (ORDER BY t2.nums) AS nums
FROM random_data t1
CROSS JOIN random_data t2
), coupons AS
(
SELECT NTILE(10) OVER (ORDER BY nums) AS group_id,
'Coupon' CONVERT(VARCHAR(10),nums) AS Coupon,
nums
FROM more_random_data
), coupons_with_join_id AS
(
SELECT ROW_NUMBER() OVER (PARTITION BY group_id ORDER BY nums) AS join_id,
Coupon
FROM coupons
)
SELECT StoreName, StoreAddress, Coupon
FROM store_info AS si
JOIN coupons_with_join_id AS cwji
ON si.join_id = cwji.join_id
ORDER BY si.join_id, Coupon
Ответ №3:
Неотъемлемая проблема здесь заключается в том, что эти 2 таблицы не имеют никакого отношения друг к другу. Таким образом, ваши варианты — либо принудительно установить псевдо-отношение, как показано в других ответах, либо создать отношение между двумя таблицами, например, добавив столбец имя_магазина в таблицу купонов.
Ответ №4:
Это распределяет все купоны (почти) равномерно по всем адресам:
with addr as
( -- prepare addresses by adding a sequence
select Name, Address,
-- 1-n
row_number() over (order by name) as rn
from table1
)
,coup as
( -- prepare coupons by adding same "sequence"
select coupons,
-- 1-n, same number of coupons ( /-1) for each address
ntile((select count(*) from table1))
over (order by coupons) as num
from table2
)
select *
from addr
join coup
on addr.rn = coup.num