Как мне выбрать 100 записей из одной таблицы для каждой уникальной записи из другой

#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