For*_*ine 5 sql-server query t-sql
为可怕的标题道歉。我想不出更好的方法来简要描述这个问题。
这是场景:
用户可以根据订单的客户、贷款类型、银行、定价区域和服务设置要附加到工作订单的服务说明。使用以下参数设置服务说明:
下面描述的 service_instruction 表的列中的值 1 等同于“全部”。
表结构(相关部分无论如何):
order (order_num INT PRIMARY KEY, client_num INT, loan_type INT,
bank_num INT, pricing_region INT)
work_order_line(work_order_line_num INT PRIMARY KEY, order_num INT, service_num INT,
description TEXT)
service_instruction(instruction_num INT PRIMARY KEY, service_num INT,
service_description TEXT, client_num INT NULL,
bank_num INT NULL, region_num INT, loan_type_cd TINYINT)
Run Code Online (Sandbox Code Playgroud)
我需要编写一个脚本,该脚本将为服务选择最具体的指令(如果存在)。例如:
用户已设置如下服务说明:
客户端 1、区域 3 和服务 A 的订单应附加“Do work B”。客户端 2、区域 3 和服务 A 的订单应附加“Do work A”。服务 B 的订单不应附加任何内容。等等。
目前这是在代码中完成的,但情况需要编写脚本。有没有一种方法可以比我正在处理的 IF..ELSE 和 ISNULL 的当前混乱更优雅(并且可能具有更好的性能)?
编辑:这是一些示例数据。
服务指令:
instruction_num | service_num | instruction_desc | bank_num | region_num | loan_type_cd | client_num
3 251 'Take the photos, yeah' 17 96 3 1
4 251 'Bid for debris removal.' 1 471 1 7
7 251 'Bid for debris removal. 1 3 1 1
Do not perform'
Run Code Online (Sandbox Code Playgroud)
[命令]:
order_num | client_num | loan_type | bank_num | pricing_region
1 3 1 1 3
2 7 3 1 471
3 2 3 17 96
4 5 2 6 17
Run Code Online (Sandbox Code Playgroud)
工作订单行:
work_order_line_num | order_num | service_num | description
20 1 251 NULL
21 2 251 NULL
22 3 251 NULL
26 4 251 NULL
Run Code Online (Sandbox Code Playgroud)
最终结果将是:
工作订单行:
work_order_line_num | order_num | service_num | description
20 1 251 'Bid for debris removal. Do not perform.'
21 2 251 'Bid for debris removal.'
22 3 251 'Take the photos, yeah'
26 4 251 'Bid for debris removal. Do not perform.'
Run Code Online (Sandbox Code Playgroud)
service_instruction 中client_num、bank_num 或loan_type_cd 的值为1 表示它分别适用于所有客户、银行或贷款类型。更复杂的是,service_instruction 中的定价区域取决于客户端。例如,当client_num 为1(“所有客户端”)时,region_num 为3 表示“所有区域”。当client_num 为3 时,region_num 39 为“所有区域”。我并不是真的在寻找某人为我写出脚本,更多的是在正确的概念方向上的指针,因此现在可能可以忽略这种复杂性。
这是我一直在努力解决这个问题,为简洁起见进行了一些编辑。是的,里面有一个光标。是的,它将被放置在生产环境中。不,我不高兴。这就是我来这里的原因!
--Table var. containing orders we need to update
DECLARE @order_numbers TABLE (order_num INT PRIMARY KEY
, client_num SMALLINT NOT NULL
, order_type_cd TINYINT NOT NULL
, loan_type_cd TINYINT NOT NULL
, bank_num TINYINT NOT NULL
, pricing_region INT NOT NULL
, service_num INT NOT NULL
, service_instruction_num SMALLINT NULL);
--Table containing the match data
DECLARE @instruction_matches TABLE (instruction_num SMALLINT PRIMARY KEY
, client_match TINYINT
, loan_type_match BIT
, bank_match BIT
, region_match BIT
, total_matches TINYINT);
DECLARE @best_instruction SMALLINT
, @order_num INT
, @client_num SMALLINT
, @loan_type_cd TINYINT
, @bank_num TINYINT
, @region_num INT
, @service_num INT;
--Get the orders to update
INSERT INTO @order_numbers (order_num
, client_num
, order_type_cd
, loan_type_cd
, bank_num
, pricing_region
, service_num)
SELECT o.order_num, oc.client_num, o.order_type_cd, oc.loan_type_cd, oc.bank_num, oc.pricing_region, wol.service_num
FROM [order] o
inner join order_context oc ON o.context_num = oc.context_num
inner join work_order_line wol ON o.order_num = wol.order_num
WHERE o.status_cd = 1 AND o.exchange_status_cd = 2 AND o.received_from_hub_ind = 1
AND o.viewed_dt IS NULL
DECLARE o_cursor CURSOR LOCAL
FOR SELECT order_num FROM @order_numbers;
OPEN o_cursor;
FETCH NEXT FROM o_cursor
INTO @order_num;
WHILE @@FETCH_STATUS = 0
BEGIN
SET @service_num = (SELECT service_num FROM @order_numbers WHERE order_num = @order_num);
SET @client_num = (SELECT client_num FROM @order_numbers WHERE order_num = @order_num);
SET @loan_type_cd = (SELECT loan_type_cd FROM @order_numbers WHERE order_num = @order_num);
SET @bank_num = (SELECT bank_num FROM @order_numbers WHERE order_num = @order_num);
SET @region_num = (SELECT pricing_region FROM @order_numbers WHERE order_num = @order_num);
INSERT INTO @instruction_matches (instruction_num, client_match, loan_type_match, bank_match, region_match)
SELECT
instruction_num
, CASE
WHEN client_num = @client_num OR client_num = 1
THEN 1
ELSE 0
END
, CASE
WHEN loan_type_cd = @loan_type_cd OR loan_type_cd = 1
THEN 1
ELSE 0
END
, CASE
WHEN bank_num = @bank_num OR bank_num = 1
THEN 1
ELSE 0
END
, CASE -- region_num = 4 means INSPECTIONS ONLY. will need to be re-written for pres.
WHEN region_num = @region_num
OR (client_num != 1 AND region_num = (SELECT region_num FROM region
WHERE client_num = @client_num
AND region_type_cd = 2
AND order_item_type_cd = 2
AND region_id = 1)
)
THEN 2
WHEN client_num = 1 AND region_num = 4
THEN 1
ELSE 0
END
FROM service_instruction
WHERE service_num = @service_num;
UPDATE @instruction_matches
SET total_matches = (client_match + loan_type_match + bank_match + region_match);
SET @best_instruction = (SELECT TOP(1) instruction_num FROM @instruction_matches ORDER BY total_matches DESC);
UPDATE @order_numbers
SET service_instruction_num = @best_instruction
WHERE order_num = @order_num;
FETCH NEXT FROM o_cursor
INTO @order_num;
END;
Run Code Online (Sandbox Code Playgroud)
我的第一步是service_instruction
按特异性/一般性进行排名 - 我认为您没有提供足够的信息来确定您所追求的内容,但假设它是基于1
s 的数量并且关系被打破:bank_num
更具体比loan_type_cd
更具体client_num
:
select *, row_number() over ( order by case when bank_num=1 then 1 else 0 end+
case when loan_type_cd=1 then 1 else 0 end+
case when client_num=1 then 1 else 0 end,
case when bank_num=1 then 1 else 0 end,
case when loan_type_cd=1 then 1 else 0 end,
case when client_num=1 then 1 else 0 end ) as gen
from service_instruction;
Run Code Online (Sandbox Code Playgroud)
产生:
instruction_num service_num instruction_desc bank_num region_num loan_type_cd client_num gen
3 251 Take the photos, yeah 17 96 3 1 1
4 251 Bid for debris removal. 1 471 1 7 2
7 251 Bid for debris removal. Do not perform 1 3 1 1 3
Run Code Online (Sandbox Code Playgroud)
然后可以将其连接到order
and并过滤每个具有最低通用性 ( )work_order_line
的行,也许是这样的:work_order_line_num
gen
with w as (
select *, row_number() over ( order by case when bank_num=1 then 1 else 0 end+
case when loan_type_cd=1 then 1 else 0 end+
case when client_num=1 then 1 else 0 end,
case when bank_num=1 then 1 else 0 end,
case when loan_type_cd=1 then 1 else 0 end,
case when client_num=1 then 1 else 0 end ) as gen
from service_instruction )
select *
from( select l.*, instruction_desc, row_number() over ( partition by l.work_order_line_num,
l.order_num,
l.service_num
order by gen ) as gen_rank
from work_order_line l join [order] o on(o.order_num=l.order_num)
join w on( l.service_num=w.service_num
and (o.bank_num=w.bank_num or w.bank_num=1)
and (o.loan_type_cd=w.loan_type_cd or w.loan_type_cd=1)
and (o.client_num=w.client_num or w.client_num=1)) ) z
where gen_rank=1
Run Code Online (Sandbox Code Playgroud)
其产生:
work_order_line_num order_num service_num instruction_desc gen_rank
20 1 251 Bid for debris removal. Do not perform 1
21 2 251 Bid for debris removal. 1
22 3 251 Take the photos, yeah 1
26 4 251 Bid for debris removal. Do not perform 1
Run Code Online (Sandbox Code Playgroud)
笔记:
work_order_line_num
,order_num
但service_num
也许并非全部都是必要的,具体取决于 PKwork_order_line
pricing_region
您提到的复杂性,但没有完全指定 - 希望您能够以与其余部分类似的方式将其处理到查询中 归档时间: |
|
查看次数: |
1523 次 |
最近记录: |