我需要编写一个查询扫描2个表的查询,如果它们具有一定条件,则在一个表中自连接后的记录不应出现在第二个表中。
如果收到订单,我们会插入到UniqueReference表中,该表对参考组合(data1,data2,reference,identifier)有唯一约束 但可能是订单被拒绝或取消,下一个订单可能会带有相同的参考组合。我必须确保我仍然允许它。
我在下面举例说明测试数据:
UniqueReference Table
-------
sequence data1 data2 key reference identifier
1 XYZB ABCD 234 Reference1 ID2
2 XYZB DCBF 456 Reference2 ID2
3 XYZB null 678 Reference3 null
4 XYZB ABCD 980 Reference1 ID2
Order Table
--------
sequence key status
1 234 Created
2 456 Rejected
3 789 Processed
4 980 Cancelled
5 678 Processing
现在,当我收到一个带有参考组合(XYZB,ABCD,Reference1,ID2)的订单(比如说密钥980)时,上面有两个数据集,那么系统不应该允许该订单(它是重复的)因为我们之前收到过这样的订单使用其状态未被拒绝的键(234)。但是如果我们收到组合的新订单(XYZB,DCBF,Reference2,ID2),那么我们应该允许这个订单,因为我们确实在系统中有该订单,但其状态为Rejected。
我需要像
这样的东西Select count(*) from Order o where o.status <> 'Rejected' and o.key in
(select <self-join> on reference combination on key for newly received order)
答案 0 :(得分:0)
我认为你大部分都对此设置感到困惑。
至于UniqueReference
表。如果你说组合data1, data2, reference, identifier
是独一无二的,那么它应该只是:UNIQUE。无所谓也不应该关心其他地方发生的事情。
备注:我假设key
字段也是唯一的,如果是,我想知道你为什么不简单地使用autonumber / identity / ...分配到sequence
列,它没有真正的价值恕我直言。现在我不知道你是如何产生这些key
值的。
现在对于Order
表,您可以预见到这样的逻辑:如果我们还没有此key
的先前记录,则允许INSERT操作。如果有前一个,找到最新的一个,如果它显示为“已取消”,则允许INSERT。否则我们总是阻止INSERT。
我不确定你是怎么想这样做的,但我想在这种情况下存储过程是有意义的。
PS:这个代码远非完美(对于初学者,它没有经过测试!),没有错误处理,可能会进行相当多的优化(例如通过合并某些操作,减少分支等)。但是我觉得它的冗长使它更容易阅读,因为过早的优化是所有邪恶的根源,你可能想要先解决这个问题,并在结果太慢时根据需要进行优化。(因为你没有提到RDBMS,我使用的是T-SQL语法,但我认为它足够通用,可以在大多数系统上运行并进行微调......)
CREATE PROCEDURE p_insert_order (
@data1 varchar(100),
@data2 varchar(100),
@reference varchar(100),
@identifier varchar(100),
@status varchar(100)
)
AS
DECLARE @key int,
@is_new_key bit,
@allow_insert bit,
@last_status varchar(100)
SELECT @key = NULL,
@is_new_key = 0,
@allow_insert = 0,
@last_status = NULL
BEGIN TRANSACTION
-- do we already have a key for this combination?
SELECT @key = [key]
FROM [UniqueReference] WITH (UPDLOCK, HOLDLOCK)
WHERE data1 = @data1
AND data2 = @data2
AND reference = @reference
AND identifier = @identifier
IF @key IS NULL
BEGIN
SELECT @is_new_key = 1,
@key = 0 -- ??? -- I have no clue how you come up with these so I'm going to leave it open
INSERT [UniqueReference] (data1, data2, reference, identifier, [key])
VALUES (@data1, @data2, @reference, @identifier, @key)
END
-- do we allow insert?
SELECT @allow_insert = @is_new_key
IF @allow_insert = 0
BEGIN
SELECT TOP 1 @last_status = [status]
FROM [Order] WITH (UPDLOCK, HOLDLOCK)
WHERE [key] = @key
ORDER BY sequence DESC
SELECT @allow_insert = 1
WHERE @last_status IS NULL
OR @last_status = 'Rejected'
END
-- do we do insert?
IF @allow_insert = 1
BEGIN
INSERT [Order] ([key], [status])
VALUES (@key, @status)
END
COMMIT TRANSACTION
Return(0)
PS:尽量避免使用保留字Order
,key
,status
,...
答案 1 :(得分:0)
首先,您必须将key
表中的UniqueReference
列添加到唯一约束中,以便它(data1,data2,reference,identifier,key)
然后您可以使用此查询
;with
old_orders as (
select distinct data1, data2, [reference], [identifier]
from UniqueReference u
where not exists(select top 1 1 from Order o where u.[key] = o.[key] and o.status in ('Cancelled','Rejected'))
)
insert into @UniqueReference (data1, data2, [reference], [identifier], [key])
select @data1, @data2, @reference, @identifier, @key
where exists (
select @data1, @data2, @reference, @identifier
except
select * from old_orders o
)
使用这些值,插入将被拒绝
declare
@data1 varchar(4)='XYZB',
@data2 varchar(4)='ABCD',
@key int = 980,
@reference varchar(10)='Reference1',
@identifier varchar(4)='ID2'
使用这些值将接受插入
declare
@data1 varchar(4)='XYZB',
@data2 varchar(4)='DCBF',
@key int = 999,
@reference varchar(10)='Reference2',
@identifier varchar(4)='ID2'