2013-08-24 4 views
2

У меня есть одна таблица (customerselection), в котором перечислены номера клиентов и промо-коды:SQL Server - Уникально обновление одной таблицы на основе категории записей в другой таблице

CustomerNumber | Promo 
12345   | ABCDEF 
54321   | BCDEFG 
22334   | BCDEFG 
54678   | BCDEFG 
23454   | ABCDEF 

И еще одну таблицу (сертификаты), что список сертификатов, Promos и CustomerNumbers, но CustomerNumber изначально NULL:

Certificate | Promo | CustomerNumber 
1111111111 | ABCDEF | NULL 
2222222222 | BCDEFG | NULL 
3333333333 | BCDEFG | NULL 
4444444444 | ABCDEF | NULL 

Что мне нужно сделать, это однозначно присвоить каждому сертификат во второй таблице в у.е. stomer в первой таблице. Акции должны соответствовать. Обновите вторую таблицу с номером клиента от первой, только до одной записи, с соответствующим промо.

Я делал это в прошлом с помощью программы VB - перебираю записи в первой таблице, обновляю первую бесплатную запись для соответствующего промо во второй таблице. Но эта программа слишком долго работает (обычно около 600 000 записей).

Есть ли способ сделать это прямо в SQL? Выполнять задачу с помощью чрезвычайно сложного (или даже просто простого) SQL-запроса? (Или функциональность SQL Server?)

ОБНОВЛЕНИЕ В каждом промо есть много сертификатов. И много клиентов за промо.

Но каждому клиенту может быть присвоен только один сертификат.

UPDATE 2 Давайте назовем первую таблицу customerselection и вторую таблицу сертификатов.

customerselection - это выбор клиентов, которым мы хотим присвоить сертификаты.

сертификаты - это пул сертификатов, которые могут быть назначены.

ответ

1

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

 custD, custR, custA 
cert2 * 
cert1   * 
cert3     * 
cert6 
cert7 

Важно в том, что каждая строка и каждый столбец имеет не более одного матча.

update certificates 
set CustomerNumber = t_cust.CustomerNumber 
from certificates,  
(select Promo, CustomerNumber, 
    row_number() over (partition by Promo order by CustomerNumber) as order_cust 
    from customerselection 
) t_cust, 
(select Promo, Certificate, 
    row_number() over (partition by Promo order by Certificate) as order_cert 
    from certificates 
) t_cert 
where t_cust.Promo = t_cert.Promo 
    and t_cust.order_cust = t_cert.order_cert 
    and certificates.Certificate = t_cert.Certificate 
+0

Я получаю синтаксическую ошибку с этим. –

+0

исправлено, забыл что-то запятые и имена таблиц не были согласованы, извините – bwt

1

Попробуйте это

UPDATE 
    B 
SET 
    B.CustomerNumber = A.CustomerNumber 
FROM 
    TableB B 
INNER JOIN 
    TableA A 
ON 
    B.Promo = A.Promo 
0

Вызывать таблицы как А и В, и из вашего вопроса, я понимаю, что может быть более чем один сертификат для каждого промо в таблице В. Таким образом, я выбрал первую запись с меньшим количеством сертификатов из B и сопоставил его с A. И соответствующим образом обновил номер клиента B.

Вот sqlfiddle для решения я разместил http://www.sqlfiddle.com/#!6/726a6/30

UPDATE B 
    SET B.CustomerNumber = A.CustomerNumber 
    FROM A, 
    (SELECT * FROM (
    SELECT b.*, ROW_NUMBER () OVER (partition BY Promo ORDER BY certificate) AS row_num 
      FROM B b 

) t WHERE row_num = 1) AS r 

    WHERE A.Promo=r.promo 
and b.CustomerNumber is null; 
+0

В предложении WHERE мне нужно явно исключить сертификат, который уже имеет присвоенное имя? Или база данных обрабатывает это, поскольку это все одна операция? –

+0

@GregHolmes Ну, да, вам нужно, я предположил, что все номера клиентов пустые. Пересмотрит мой ответ через пару минут. – Bren

+0

Отредактировав ответ, я думаю, что так и будет. – Bren

0

Поскольку вопрос был обновлен, я должен обновить мой ответ слишком

Declare @c table (CustomerNumber int, Promo Varchar(50)) 
Insert into @c 
SELECT 12345 ,'ABCDEF' 
UNION SELECT 54321,'BCDEFG' 
UNION SELECT 54321,'XXXXXX' 
UNION SELECT 77777,'XXXXXX' 


Declare @ce table (Certificate bigint,Promo Varchar(50), CustomerNumber int) 
insert into @ce 
SELECT 1111111111,'ABCDEF',NULL 
UNION SELECT 2222222222,'BCDEFG',NULL 
UNION SELECT 3333333333,'XXXXXX',NULL 
UNION SELECT 4444444444,'ABCEDF',NULL 


Update ce set CustomerNumber = z.CustomerNumber 
from 
(
Select CustomerNumber,Certificate from 
(select *,ROW_NUMBER() over (order by CustomerNumber) as rn 
from 
(
Select DISTINCT CustomerNumber from @c 
) x)x 
JOIN 
(Select *,ROW_NUMBER() over (order by Certificate) as rn from 
(
Select DISTINCT Certificate 
from @ce) y 
) y on x.rn=y.rn 
) z join @ce ce on ce.Certificate=z.Certificate 

Select * from @ce 
0

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

Ключ должен перечислить как столы на промо.Затем сделайте матч по номеру:

with toupdate as (
     select c.*, row_number() over (partition by Promo order by newid()) as seqnum 
     from Certificates c 
    ), 
    customers as (
     select cs.*, row_number() over (partition by Promo order by newid()) as seqnum 
     from customerselection cs 
    ) 
update toupdate 
    set CustomerNumber = customers.CustomerNumber 
    from toupdate join 
     customers 
     on toupdate.promo = customers.promo and 
      toupdate.seqnum = customers.seqnum; 

Это гарантирует, что один клиент не получает повторится в ту же акцию, если клиент имеет две строки в таблице customerselection.

+0

Я не был достаточно ясен в своем вопросе ... каждому клиенту нужно присвоить один и только один сертификат. Промо обязательно нужно соответствовать, но конечный один к одному является клиентом сертификата. –