2

我有一张表(customerselection),其中列出了客户编号和促销代码:

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

另一个表(证书)列出了证书、促销和客户编号,但客户编号最初为 NULL:

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

我需要做的是将第二个表中的每个证书唯一地分配给第一个表中的客户。促销需要匹配。使用匹配促销的第一个客户编号更新第二个表,仅更新到一个记录。

我过去使用 VB 程序完成了此操作 - 循环第一个表中的记录,更新第二个表中匹配促销的第一个免费记录。但是该程序运行时间太长(通常有大约 600,000 条记录)。

有没有办法在 SQL 中做到这一点?用一个非常复杂(甚至非常简单)的 SQL 查询来完成任务?(或 SQL Server 功能?)

更新每个促销都有许多证书。每个促销活动都有很多客户。

但是每个客户只能分配一个证书。

更新 2 让我们调用第一个表customerselection和第二个表证书

customerelection是我们要为其分配证书的客户的选择。

证书是可以分配的证书池。

4

5 回答 5

1

尝试这个

UPDATE
    B 
SET
    B.CustomerNumber = A.CustomerNumber
FROM
    TableB B
INNER JOIN
    TableA A
ON 
    B.Promo = A.Promo
于 2013-08-24T10:54:41.933 回答
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
于 2013-08-24T12:17:55.893 回答
0

将表称为 A 和 B,根据您的问题,我了解到表 B 中的每个促销可能有多个证书。所以我从 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;
于 2013-08-24T10:55:31.237 回答
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
于 2013-08-24T11:02:54.627 回答
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表中有两行。

于 2013-08-24T11:37:18.983 回答